Skip to content

fix: server sdk could send user agent headers under a different header name - #1860

Open
joker23 wants to merge 1 commit into
mainfrom
skz/sdk-2908/oxygen-user-agent-header
Open

fix: server sdk could send user agent headers under a different header name#1860
joker23 wants to merge 1 commit into
mainfrom
skz/sdk-2908/oxygen-user-agent-header

Conversation

@joker23

@joker23 joker23 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

This PR will make it so that server side sdks can also determine the header name used to send user agent value. The reason we need this is that the default user-agent header name could be blocked by different platforms/configurations which causes us to lose usage data.

This is currently delivered as an internal implementation detail to address issues with the shopify oxygen sdk not sending usage data.


Note

Overview
Adds an internal userAgentHeaderName option on the server SDK so the SDK version string can be sent under a custom header instead of the default user-agent, which some platforms block and breaks usage telemetry.

LDClientImpl threads this value into defaultHeaders for both FDv1 and FDv2 construction paths (events, polling, streaming requestors share the same base headers). When no override is set, behavior stays user-agent.

The Shopify Oxygen SDK sets x-launchdarkly-user-agent by default so Oxygen runtimes can report usage without relying on user-agent.

New tests cover events flush, polling, default header name, and Oxygen EventProcessor base headers.

Reviewed by Cursor Bugbot for commit 91b3508. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions

Copy link
Copy Markdown
Contributor

@launchdarkly/js-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 26360 bytes
Compressed size limit: 29000
Uncompressed size: 129188 bytes

@github-actions

Copy link
Copy Markdown
Contributor

@launchdarkly/js-client-sdk size report
This is the brotli compressed size of the ESM build.
Compressed size: 32444 bytes
Compressed size limit: 34000
Uncompressed size: 116232 bytes

@github-actions

Copy link
Copy Markdown
Contributor

@launchdarkly/browser size report
This is the brotli compressed size of the ESM build.
Compressed size: 179887 bytes
Compressed size limit: 200000
Uncompressed size: 833430 bytes

@github-actions

Copy link
Copy Markdown
Contributor

@launchdarkly/js-client-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 41502 bytes
Compressed size limit: 44000
Uncompressed size: 224541 bytes

@joker23

joker23 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 91b3508. Configure here.

@joker23
joker23 marked this pull request as ready for review August 13, 2026 20:24
@joker23
joker23 requested a review from a team as a code owner August 13, 2026 20:24

@devin-ai-integration devin-ai-integration Bot left a comment

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.

Devin Review found 1 potential issue.

View 1 additional finding in Devin Review.

Open in Devin Review

import TestLogger from './Logger';
import makeCallbacks from './makeCallbacks';

describe('LDClientImpl user-agent header name', () => {

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.

🟡 New test file groups tests in a wrapper block without any shared setup, against repo test conventions

The new test file wraps three independent tests in a grouping block (describe(...) at packages/shared/sdk-server/__tests__/LDClientImpl.userAgentHeaderName.test.ts:6) even though each test builds its own setup, which the repository's testing rules forbid.
Impact: Test organization diverges from the required repository conventions.

Convention: describe blocks only for shared setup

Both .cursor/rules/testing.mdc and CLAUDE.md state: "Describe blocks should ONLY be used for common setup for a series of tests" and "If there is no shared configuration, do not use a describe block". In this file each of the three it blocks independently calls createBasicPlatform(), sets up the fetch mock, and constructs its own LDClientImpl, so there is no shared setup in the describe. The test names already read as full sentences on their own.

Prompt for agents
The new test file packages/shared/sdk-server/__tests__/LDClientImpl.userAgentHeaderName.test.ts wraps three self-contained tests in a describe block, but no setup is shared between them (each test creates its own platform, fetch mock, and client). Repository rules (.cursor/rules/testing.mdc, CLAUDE.md) say describe blocks should only be used when there is common setup. Either remove the describe block and make the individual test names fully self-describing, or move the common platform/client construction into shared setup inside the describe.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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.

Yeah, I agree with Devin and its dislike of this vacuous testing structure. 😉

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.

But, really, please change them to only group for shared setup.

import TestLogger from './Logger';
import makeCallbacks from './makeCallbacks';

describe('LDClientImpl user-agent header name', () => {

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.

Yeah, I agree with Devin and its dislike of this vacuous testing structure. 😉

import TestLogger from './Logger';
import makeCallbacks from './makeCallbacks';

describe('LDClientImpl user-agent header name', () => {

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.

But, really, please change them to only group for shared setup.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants