Skip to content

Add X-YVP-Sdk header and additionalHeaders override#237

Merged
Kyleasmth merged 6 commits into
mainfrom
ks/YPE-2295-react-sdk-add-x-yvp-sdk-http-header-for-version
May 21, 2026
Merged

Add X-YVP-Sdk header and additionalHeaders override#237
Kyleasmth merged 6 commits into
mainfrom
ks/YPE-2295-react-sdk-add-x-yvp-sdk-http-header-for-version

Conversation

@Kyleasmth
Copy link
Copy Markdown
Collaborator

@Kyleasmth Kyleasmth commented May 14, 2026

Summary

  • Sends X-YVP-Sdk: ReactSDK={version} on every API call alongside X-YVP-App-Key, so the data team can attribute traffic to this SDK.
  • Version is read from a single constant (packages/core/src/version.ts). Local/dev builds keep Dev so they're filterable in the data lake; the release script stamps the precise version from packages/core/package.json before the publishing build runs.
  • New additionalHeaders prop on YouVersionProvider (and additionalHeaders field on ApiConfig) merges into every request and overrides built-in headers on key collision. This unblocks the React Native Expo wrapper Cameron flagged on Teams — they can swap X-YVP-Sdk: ReactSDK=... for X-YVP-Sdk: ReactNativeSDK={their version}.

Implementation notes

  • Header added in both ApiClient.defaultHeaders (the main HTTP path) and YouVersionAPI.addStandardHeaders (the static helper, used by the PKCE auth flow). Both call sites that previously set X-YVP-App-Key now also set X-YVP-Sdk.
  • Override semantics: config.additionalHeaders is spread last into defaultHeaders, so caller-supplied values win.
  • Threaded through YouVersionContextuseBibleClient / useLanguageClient / useHighlights. Provider memoizes the headers object via JSON.stringify so inline object literals don't churn the hook memos.
  • Release-time stamping is a Node script invoked by the root release script, with turbo build --force to bypass the cache from the workflow's earlier (unstamped) build.

Known scope gap

Auth requests via SignInWithYouVersionPKCE use the static YouVersionPlatformConfiguration, not ApiConfig. They send X-YVP-Sdk correctly but don't honor a provider-level additionalHeaders override. Out of scope for this ticket auth is typically an OS-level redirect for the React Native case anyway.

Test plan

  • pnpm typecheck clean across all packages
  • pnpm lint clean across all packages
  • pnpm test — 510 tests pass (includes 5 new core cases and 1 new hooks case)
  • Manual: pnpm dev:web, open the Next.js example, hit any Bible API call, verify in DevTools → Network:
    • X-Yvp-Sdk: ReactSDK=Dev
    • X-Yvp-App-Key: <your key>
  • Manual override: add additionalHeaders={{ 'X-YVP-Sdk': 'ReactNativeSDK=test' }} to <YouVersionProvider> in the example app, confirm header value swaps on the wire
  • Release stamping: smoke-tested locally — node scripts/stamp-sdk-version.mjs reads packages/core/package.json version and rewrites packages/core/src/version.ts. The first published version after merge should land with the real semver instead of Dev.

Changeset

.changeset/x-yvp-sdk-header.md — minor bump for core / hooks / ui (kept in lockstep per fixed: config).

Greptile Summary

This PR attaches an X-YVP-Sdk: ReactSDK={version} header to every API call and adds an additionalHeaders escape hatch on both ApiConfig and YouVersionProvider so wrappers (e.g. the React Native Expo SDK) can substitute their own identifier. The version is read at build time by importing packages/core/package.json directly in version.ts.

  • Header stamping: X-YVP-Sdk is now set in both ApiClient.defaultHeaders (HTTP path) and YouVersionAPI.addStandardHeaders (static PKCE auth path). additionalHeaders are spread last so caller-supplied values always win on key collision.
  • Context threading: YouVersionProvider stabilises the additionalHeaders reference via useMemo keyed on a sorted JSON.stringify of entries, preventing unnecessary ApiClient reconstructions from inline object literals. All three hooks (useBibleClient, useLanguageClient, useHighlights) forward additionalHeaders into their ApiClient instances and include it in their memo dependency arrays.
  • Testing: 5 new ApiClient unit tests, 1 new hook test, and a new UI provider test file cover the header pass-through and override semantics.

Confidence Score: 5/5

Safe to merge. All three API call paths correctly emit the new header, additionalHeaders override semantics work as documented, and the stability memo correctly guards against unnecessary ApiClient reconstructions.

The header wiring is consistent across ApiClient, YouVersionAPI, and all three hooks. The useMemo key-sorting strategy correctly handles insertion-order sensitivity. No incorrect data, dropped state, or auth boundary issues were found in the changed paths.

No files require special attention. The only gap is missing parallel tests for useLanguageClient and useHighlights with additionalHeaders.

Important Files Changed

Filename Overview
packages/core/src/version.ts New file; exports SDK constants and a header-value builder by reading version directly from package.json via JSON import assertion. Clean and straightforward.
packages/core/src/client.ts Adds X-YVP-Sdk header and spreads additionalHeaders last into defaultHeaders so callers can override built-ins. Spread of undefined is a safe no-op in JS.
packages/core/src/YouVersionAPI.ts Adds X-YVP-Sdk to the static auth-flow header builder. additionalHeaders are not supported here (acknowledged as known scope gap).
packages/hooks/src/context/YouVersionProvider.tsx Threads additionalHeaders through context with a stability memo keyed on sorted JSON.stringify to avoid churn from inline object literals. The ESLint suppression is justified.
packages/hooks/src/useBibleClient.ts Passes additionalHeaders from context into ApiClient config and includes it in the useMemo dependency array. Correctly mirrors the pattern in useHighlights and useLanguageClient.
packages/hooks/src/useHighlights.ts Same additionalHeaders wiring as useBibleClient. No issues.
packages/hooks/src/useLanguageClient.ts Same additionalHeaders wiring as useBibleClient. No issues.
packages/core/src/tests/client.test.ts New test cases cover X-YVP-Sdk header presence, additionalHeaders pass-through, and override semantics. Well-structured with MSW interceptors.
packages/hooks/src/useBibleClient.test.tsx New test verifies additionalHeaders flows from context into ApiClient constructor. Coverage is good for this hook, though useLanguageClient and useHighlights lack matching tests.
packages/ui/src/components/YouVersionProvider.test.tsx New test file; verifies the UI wrapper forwards additionalHeaders to the underlying hooks provider and omits it when not provided.
packages/core/src/types/index.ts Adds optional additionalHeaders field to ApiConfig with clear JSDoc explaining override semantics.
packages/hooks/src/context/YouVersionContext.tsx Adds additionalHeaders to the context data shape. Straightforward type addition.
packages/core/src/index.ts Re-exports everything from version.ts to make SDK_VERSION, SDK_NAME, and SDK_VERSION_HEADER_NAME available to consumers.
.changeset/x-yvp-sdk-header.md Proper minor bump for core/hooks/ui in lockstep, consistent with the unified versioning strategy.

Sequence Diagram

sequenceDiagram
    participant App as Consumer App
    participant YVP as YouVersionProvider
    participant Ctx as YouVersionContext
    participant Hook as useBibleClient / useLanguageClient / useHighlights
    participant AC as ApiClient
    participant API as YouVersion API

    App->>YVP: render(appKey, additionalHeaders)
    YVP->>YVP: "stableAdditionalHeaders = useMemo(sorted JSON key)"
    YVP->>Ctx: "provide({ appKey, additionalHeaders: stableAdditionalHeaders })"
    Hook->>Ctx: useContext()
    Hook->>AC: "new ApiClient({ appKey, additionalHeaders })"
    AC->>AC: "defaultHeaders = { X-YVP-App-Key, X-YVP-Sdk: ReactSDK={version}, ...additionalHeaders }"
    Hook->>API: GET /resource (headers: defaultHeaders)
    API-->>Hook: 200 OK

    Note over App,API: additionalHeaders override built-ins on key collision
Loading

Fix All in Claude Code Fix All in Cursor

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/hooks/src/useBibleClient.test.tsx:96-125
**Missing coverage for `useLanguageClient` and `useHighlights`**

`useBibleClient` gets a dedicated `additionalHeaders` test, but `useLanguageClient` and `useHighlights` received identical wiring changes and have no matching test. If someone accidentally drops `additionalHeaders` from one of those hooks' `useMemo` call or dep array in a future refactor, the regression would go undetected.

Reviews (6): Last reviewed commit: "YPE-2295: Test additionalHeaders pass-th..." | Re-trigger Greptile

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 14, 2026

🦋 Changeset detected

Latest commit: a9f19de

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

This PR includes changesets to release 4 packages
Name Type
@youversion/platform-core Minor
@youversion/platform-react-hooks Minor
@youversion/platform-react-ui Minor
vite-react Patch

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

@Kyleasmth Kyleasmth requested a review from cameronapak May 14, 2026 18:46
@Kyleasmth Kyleasmth marked this pull request as ready for review May 14, 2026 18:46
greptile-apps[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Collaborator

@cameronapak cameronapak left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

cameronapak
cameronapak previously approved these changes May 15, 2026
Copy link
Copy Markdown
Collaborator

@cameronapak cameronapak left a comment

Choose a reason for hiding this comment

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

Everything looks good to me. I'm considering the script and if it's needed, but... nothing blocking. Good work!

Comment thread scripts/stamp-sdk-version.mjs Outdated
Comment thread packages/core/tsup.config.ts Outdated
@Kyleasmth Kyleasmth force-pushed the ks/YPE-2295-react-sdk-add-x-yvp-sdk-http-header-for-version branch from d96d92c to 21e3152 Compare May 15, 2026 18:28
cameronapak
cameronapak previously approved these changes May 15, 2026
Copy link
Copy Markdown
Collaborator

@cameronapak cameronapak left a comment

Choose a reason for hiding this comment

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

LGTM!

@cameronapak
Copy link
Copy Markdown
Collaborator

I think you'll need to rebase from main to get this to resolve conflicts. You may have been using an old/stale version of main

Kyleasmth added 5 commits May 18, 2026 13:42
Replace the fragile stamp-sdk-version.mjs script with tsup's define plugin,
which injects the version from package.json at build time. This approach:
- Eliminates regex fragility
- Removes the need for --force rebuilds
- Matches the pattern used by Stripe, Sentry, AWS SDKs
- Simplifies the release pipeline

The version is injected at build time and falls back to 'Dev' at runtime
for test environments.
@Kyleasmth Kyleasmth force-pushed the ks/YPE-2295-react-sdk-add-x-yvp-sdk-http-header-for-version branch from 21e3152 to e1950d8 Compare May 18, 2026 20:57
@Kyleasmth Kyleasmth requested a review from cameronapak May 18, 2026 21:35
cameronapak
cameronapak previously approved these changes May 19, 2026
Copy link
Copy Markdown
Collaborator

@cameronapak cameronapak left a comment

Choose a reason for hiding this comment

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

LGTM

@cameronapak
Copy link
Copy Markdown
Collaborator

@Kyleasmth great work. We may need updates to the YouVersionProvider in the UI package. Can you look at that and see if it also needs the headers update?

@Kyleasmth
Copy link
Copy Markdown
Collaborator Author

@cameronapak The UI YouVersionProvider is just a thin wrapper around the hooks one (ComponentProps + {...props} spread), so it picks up additionalHeaders automatically AFAIK.

Copy link
Copy Markdown
Collaborator

@cameronapak cameronapak left a comment

Choose a reason for hiding this comment

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

LGTM, great work!

@Kyleasmth Kyleasmth merged commit 02c2330 into main May 21, 2026
6 checks passed
@Kyleasmth Kyleasmth deleted the ks/YPE-2295-react-sdk-add-x-yvp-sdk-http-header-for-version branch May 21, 2026 16:16
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