Skip to content

fix: keep a Request's own headers in withUsageHeaders - #117

Merged
scottlovegrove merged 1 commit into
mainfrom
scottl/usage-headers-request-input
Nov 11, 2026
Merged

scottlovegrove merged 1 commit into
mainfrom
scottl/usage-headers-request-input

Conversation

@scottlovegrove

Copy link
Copy Markdown
Collaborator

Summary

withUsageHeaders built init.headers from init.headers plus the usage headers only. When it was called with a Request that carries its own headers and no init.headers, fetch(request, { headers }) replaced the Request's headers with just the usage headers, so its Authorization (and anything else on it) was dropped.

The wrapper now starts from the Request's own headers when init brings none. When both are given, init.headers still wins, as it does with fetch, and the usage headers still win over either. This mirrors the same fix in the Automations CLI's fetchWithUsageHeaders.

Nothing in comms-cli passes a Request today (the OAuth provider calls the wrapped fetch with a URL string and options), so the bug was latent; this keeps the wrapper's contract true for any future caller.

Tests

New withUsageHeaders cases in src/lib/usage-tracking.test.ts. The fake fetch builds new Request(input, init) from its arguments, as the real one does, so the assertions are on the headers the request would actually go out with.

  • A Request carrying Authorization, passed with no init, keeps it alongside the usage headers. Failed before the fix (authorization missing), passes after.
  • With both a Request and init.headers, init.headers wins and a Request-only header is gone. Fails if the fix is changed to prefer the Request's headers.
  • Usage headers win over a Request's header of the same name (User-Agent).
  • init.headers on a URL input are kept alongside the usage headers.

npm run verify passes.

When `withUsageHeaders` was called with a Request carrying its own
headers and no `init.headers`, it passed `init.headers` made of only
the usage headers. `fetch(request, { headers })` replaces the
Request's headers, so its `Authorization` and anything else were lost.

Start from the Request's headers when `init` brings none. When both
are given, `init.headers` still wins, as it does with `fetch`, and the
usage headers still win over either.

Nothing in the CLI passes a Request today (the OAuth provider calls it
with a URL and options), so this was latent.
@scottlovegrove scottlovegrove self-assigned this Nov 11, 2026
@scottlovegrove
scottlovegrove merged commit d3eeac0 into main Nov 11, 2026
5 checks passed
@scottlovegrove
scottlovegrove deleted the scottl/usage-headers-request-input branch November 11, 2026 12:43
doist-release-bot Bot added a commit that referenced this pull request Nov 11, 2026
## [4.1.3](v4.1.2...v4.1.3) (2026-11-11)

### Bug Fixes

* keep a Request's own headers in withUsageHeaders ([#117](#117)) ([d3eeac0](d3eeac0))
@doist-release-bot

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 4.1.3 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant