Skip to content

Fix how headers are handled in @hey-api/client-angular#3860

Open
StratusFearMe21 wants to merge 10 commits into
hey-api:mainfrom
StratusFearMe21:fix-angular-headers
Open

Fix how headers are handled in @hey-api/client-angular#3860
StratusFearMe21 wants to merge 10 commits into
hey-api:mainfrom
StratusFearMe21:fix-angular-headers

Conversation

@StratusFearMe21
Copy link
Copy Markdown

In the current implementation of the @hey-api/client-angular client, the HTTP headers that are set before a request is made don't make it to the final HttpRequest object.

  • The headers on the HttpRequest object must be set after the opts have been fully initialized with all the HttpHeaders set
  • Because opts was being shallow cloned into the setAuthParams function, the final HttpHeaders object wasn't actually making it out of that function. I've modified the function so it returns the final HttpHeaders out.

@bolt-new-by-stackblitz
Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 9, 2026

🦋 Changeset detected

Latest commit: 4c5d311

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@hey-api/openapi-ts Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown

vercel Bot commented May 9, 2026

@StratusFearMe21 is attempting to deploy a commit to the Hey API Team on Vercel.

A member of the Team first needs to authorize it.

@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. bug 🔥 Broken or incorrect behavior. labels May 9, 2026
Copy link
Copy Markdown
Contributor

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Consider regenerating the snapshots and the bundled example, adding a changeset, and addressing the inline comments before merging. The core fix is correct and welcome — it's the surrounding plumbing that's missing.

TL;DR — The PR correctly fixes the dropped-headers bug in @hey-api/client-angular by reordering auth-application before request construction and threading the immutable HttpHeaders instance back out of setAuthParams. The fix is sound; the gaps are stale generator snapshots, a missing changeset, and one residual aliasing edge case for auth.in === 'query'.

Key changes

  • Split requestOptions into options-building and finalizeRequest — auth/validators now run between the two so the resulting HttpRequest sees post-auth headers.
  • setAuthParams returns the new HttpHeaders instance — caller reassigns opts.headers so HttpHeaders.set/append (which return new instances rather than mutating) are no longer lost across the previous shallow-copy boundary.
  • Public client.requestOptions(...) rewired — now calls finalizeRequest(requestOptions(options)).req to keep the same external contract.

Summary | 2 files | 1 commit | base: mainfix-angular-headers


Snapshots and example are stale

Before: generated snapshots and the committed openapi-ts-angular example still emit the old requestOptions (returning { opts, req, url }) and the old setAuthParams (returning void).
After: every snapshot needs the new finalizeRequest split and the new return options.headers; lines.

The Angular client bundle/client.ts and bundle/utils.ts are templated into generator output and captured as snapshots. The diff updates the source but not the 22 stale client/utils.gen.ts + client/client.gen.ts pairs under packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/clients/@hey-api/client-angular/*/client/, nor the committed example at examples/openapi-ts-angular/src/client/client/. Run pnpm tu -- @hey-api/openapi-ts and pnpm examples:generate so the regeneration ships in this PR; otherwise the snapshot tests will diff in CI.

packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/clients/@hey-api/client-angular/default/client/utils.gen.ts · examples/openapi-ts-angular/src/client/client/client.gen.ts


Missing changeset

Before: .changeset/ contains only README.md, changelog.js, config.json.
After: a fix changeset for the package owning the angular client bundle so the fix gets released.

This is a behavior-affecting bug fix to a published client. Per repo convention (Changesets) it needs a .changeset/*.md entry — e.g. precedent: PR #3814 for client interceptor changes — otherwise the fix won't ship in any version.


Pre-existing thematic bug worth folding in

Before: opts.headers.delete('Content-Type') at client.ts:85 is a no-op because HttpHeaders.delete() returns a new instance instead of mutating.
After: opts.headers = opts.headers.delete('Content-Type'); matches the pattern this PR establishes for set/append and the existing pattern in mergeHeaders (utils.ts:294).

This line is unchanged by the diff, but it's the same immutability bug the PR fixes elsewhere, on the same theme ("how headers are handled"), and means empty-body requests still send the default Content-Type: application/json. Worth a one-line fix here while you're in the file.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Claude Opus𝕏

Comment on lines 113 to 116
opts.headers = await setAuthParams({
...opts,
security: opts.security,
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Query-auth tokens still get dropped here. setAuthParams receives a shallow copy via { ...opts }; when opts.query is undefined, setAuthParams (utils.ts:200-203) does options.query = {} on the copy and writes the token into that throwaway object — the assignment never propagates back to outer opts, so finalizeRequest(opts)buildUrl(opts) runs without the query-auth params. (When opts.query is already an object, the shared reference saves you.) Either return query alongside headers from setAuthParams, pre-initialize opts.query = opts.query ?? {} before this call, or stop shallow-copying and let setAuthParams mutate opts directly.

return opts;
};

const finalizeRequest = (opts: any) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opts: any weakens the type safety that the previous inline construction had — opts is the inferred return of requestOptions and the rest of the file (e.g. line 92's cast opts as Config & RequestOptions) implicitly relies on that. Consider (opts: ReturnType<typeof requestOptions>) so the cast is the only erasure.

}

return;
return options.headers;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-existing, but worth confirming intent: return options.headers inside the for loop means only the first security entry that produces a token is applied — subsequent entries (e.g. a second scheme, or a header + cookie combination) are silently dropped. Peer clients (client-fetch/utils.ts:126-154 and friends) iterate every entry. If this PR is the right place to align, drop the inner return and keep only the post-loop one.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, you're right. I don't think that should be there

@StratusFearMe21
Copy link
Copy Markdown
Author

@pullfrog, do I need a changeset even for a bugfix?

@StratusFearMe21
Copy link
Copy Markdown
Author

@pullfrog, would this constitute a major, or a minor bump to the version?

@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. and removed size:S This PR changes 10-29 lines, ignoring generated files. labels May 9, 2026
@StratusFearMe21
Copy link
Copy Markdown
Author

@pullfrog, how's the PR looking now?

@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels May 9, 2026
@StratusFearMe21
Copy link
Copy Markdown
Author

StratusFearMe21 commented May 9, 2026

Yeah, I'm stuck. I have no clue how to regenerate the snapshots to make the CI pass. pnpm tu did something, but not enough is seems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug 🔥 Broken or incorrect behavior. size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant