-
-
Notifications
You must be signed in to change notification settings - Fork 414
fix: ESM compatibility - avoid direct Response object mutation #1430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
When using fetch in ESM environments (e.g., node-fetch v3+), the Response object is read-only and attempting to set properties like 'data' and 'error' directly throws an error. This fix creates a wrapper object that delegates to the original Response while allowing the assignment of custom properties, ensuring compatibility with both CommonJS and ESM environments. Fixes compatibility with node-fetch v3+ and other ESM-only fetch implementations.
ef1631a
to
839fb08
Compare
bugbot run |
@codex review |
@omarmciver Could you add a changeset? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting
// Create a wrapper object that doesn't mutate the Response | ||
// This ensures compatibility with ESM environments where Response is read-only | ||
const r = { | ||
data: (null as unknown) as T, | ||
error: (null as unknown) as E, | ||
// Delegate Response properties | ||
ok: response.ok, | ||
status: response.status, | ||
statusText: response.statusText, | ||
headers: response.headers, | ||
url: response.url, | ||
redirected: response.redirected, | ||
type: response.type, | ||
body: response.body, | ||
bodyUsed: response.bodyUsed, | ||
// Delegate Response methods |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep HttpResponse.bodyUsed in sync with underlying Response
The new wrapper records response.bodyUsed
once and stores the boolean on the returned object, but the response body is consumed later in the function when responseFormat
is defined. After a call resolves, data.bodyUsed
still reports the initial value (false
) even though the underlying Response
has been read and json()/text()
can no longer be called without throwing. Previously, because the original Response
instance was returned, bodyUsed
reflected the consumed state. Any client code that checks bodyUsed
to determine whether the body can be re-read will now be misled and may attempt a second read that fails.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is being reviewed by Cursor Bugbot
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
formData: () => response.formData(), | ||
json: () => response.json(), | ||
text: () => response.text(), | ||
} as HttpResponse<T, E>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: HttpResponse Wrapper Causes Compatibility Problems
The new HttpResponse
wrapper object introduces several compatibility issues. It's a plain object, which breaks instanceof Response
checks. Properties like body
and bodyUsed
are statically copied, leading to stale values, and the stream()
method is missing from the delegated Response
methods.
Summary
Fixes #1429 - Response object mutation fails in ESM environments
Problem
The Fetch client template directly mutates Response objects by adding
data
anderror
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:
data
anderror
propertiesChanges
Modified
templates/base/http-clients/fetch-http-client.ejs
to create a wrapper object instead of directly mutating the Response:Testing
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:
"type": "module"
in package.json)Without this fix, users need workarounds like wrapping fetch with a Proxy to make Response properties writable, which is not ideal.