Skip to content

feat: allow custom default headers on CommsApi - #104

Merged
roryist merged 1 commit into
mainfrom
roryist/custom-default-headers
Oct 21, 2026
Merged

roryist merged 1 commit into
mainfrom
roryist/custom-default-headers

Conversation

@roryist

@roryist roryist commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

TL;DR

Apps built on this SDK can now say who they are: a headers option on CommsApi sends extra headers (like Doist-Platform: cli) on every request. Nothing changes for existing consumers.

Why

The Comms backend tells its clients apart by the Doist-Platform header. When a request arrives without it, dashboards and logs file it under "unknown". The Comms CLI is one of those unknowns today: it sends every request through this SDK, and the SDK had no way to attach a header. The accepted platform values are growing a cli entry on the backend side, so the SDK needs a door to send it through.

What changes

before after
new CommsApi(token, { ... }) baseUrl, version, customFetch same, plus headers (new)
requests with no headers set Content-Type, Authorization, X-Request-Id unchanged
requests with headers set not possible the extra headers ride along

The only change is the new option; every request a client makes, including the multipart attachment upload, carries the configured headers. Everything else is how it already worked.

A configured header can never replace Authorization, X-Request-Id, or the multipart Content-Type — those merge on top, and a test proves it.

3 things to look at

  • The option threads through each client the same way customFetch already does, so the diff is one mechanical line per call site plus the plumbing in http-client.ts and base-client.ts.
  • migration.ts and the OAuth helpers in authentication.ts deliberately don't take the option — they aren't constructed from CommsApiOptions. They can follow if ever needed.
  • No metrics: this is a client library; the payoff shows up in the backend's existing platform attribution once consumers pass the header.

How it relates to other PRs

Doist/comms-cli#88 covers the CLI's one direct fetch today; once this ships in a release, the CLI passes headers: { 'Doist-Platform': 'cli' } to CommsApi and all its traffic is attributed.

References

  • Backend attribution: requests without Doist-Platform are logged as "unknown" (see get_current_app in Doist/comms-backend).

(Written by Rory's agent)

🤖 Generated with Claude Code

Adds a `headers` option to `CommsApiOptions`, threaded through every
client and the multipart upload helper, so SDK consumers can attribute
their traffic (e.g. `Doist-Platform: cli` for the Comms CLI). Custom
headers can never override Authorization, X-Request-Id or the
multipart Content-Type.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@doistbot doistbot left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This PR adds an optional headers option to CommsApi so apps can identify themselves (e.g. via Doist-Platform) on every request, including multipart uploads, with the SDK-managed Authorization, X-Request-Id, and multipart Content-Type headers always merging on top. The plumbing threads through the clients the same way customFetch already does, keeping the diff mechanical and non-breaking for existing consumers. No inline issues were flagged.

I also included a few optional follow-up notes in the details below.

Optional follow-up notes (2)
  • P3 src/transport/http-client.ts:39: Reserved headers are only protected case-sensitively. A caller passing authorization or x-request-id (lowercase) leaves both keys on the plain object, and fetch treats header names case-insensitively, so the request ends up with combined values such as Authorization: Bearer token, Bearer forged. Strip reserved names from customHeaders case-insensitively (or build headers with Headers.set). The same case-collision applies to the { ...customHeaders, Authorization, 'Content-Type' } merge in multipart-upload.ts.
  • P3 src/utils/multipart-upload.ts:270: The new headers argument in uploadMultipartFile has no test coverage: no test passes custom headers or asserts that Authorization/Content-Type still win. The PR description says a test proves the multipart Content-Type guarantee, but the only new test exercises httpClient.request. Add a real-server test in multipart-upload.test.ts that sends a custom header plus conflicting authorization/content-type values and asserts the SDK values are used.

Share Feedback • Review Logs

@scottlovegrove
scottlovegrove added this pull request to stack #106 October 20, 2026 16:14
@roryist roryist added the 👀 Show PR requires passing checks before merge and independent human review before or after merge. label Oct 21, 2026
@roryist
roryist marked this pull request as ready for review October 21, 2026 09:09
@roryist
roryist merged commit cdf1a5c into main Oct 21, 2026
6 checks passed
@roryist
roryist deleted the roryist/custom-default-headers branch October 21, 2026 09:09
doist-release-bot Bot added a commit that referenced this pull request Oct 21, 2026
## [3.6.0](v3.5.0...v3.6.0) (2026-10-21)

### Features

* allow custom default headers on CommsApi ([#104](#104)) ([cdf1a5c](cdf1a5c))
@doist-release-bot

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.6.0 🎉

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

released 👀 Show PR requires passing checks before merge and independent human review before or after merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants