Skip to content

feat: Add optional streaming members to the platform fetch types - #2092

Draft
joker23 wants to merge 6 commits into
mainfrom
skz/sdk-2924/platform-streaming-fetch
Draft

joker23 wants to merge 6 commits into
mainfrom
skz/sdk-2924/platform-streaming-fetch

Conversation

@joker23

@joker23 joker23 commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Extends the platform Requests types in @launchdarkly/js-sdk-common so a platform fetch implementation can serve as the SSE streaming transport for @launchdarkly/eventsource through structural typing, with no dependency between the two packages in either direction.

New members on the platform types, all optional so existing platform implementations remain valid and external implementers see no breaking change:

  • Options.streaming -- marks a streaming request: the implementation does not request compressed content, applies no request timeout, and delivers response chunks with low latency through the response body.
  • Options.signal -- an AbortSignalLike abort signal. The type resolves to the platform's own global AbortSignal when one is declared, and falls back to a minimal structural subset otherwise, which keeps the published declarations valid for consumers that compile without DOM or Node global types.
  • Response.statusText and Response.body (with the new ResponseBody and BodyReader interfaces) -- the streamable response surface.
  • Headers.forEach -- the header iteration the streaming client reads.

On the eventsource side, FetchLikeResponse.statusText and FetchHeaders.forEach become optional, so the contract -- Requests['fetch'] is assignable to FetchLike -- holds at the interface level. The client already guarded a missing statusText at runtime; headersToObject gains the matching guard for a missing forEach. Compile-level assertions in the eventsource type-compatibility tests enforce the contract and pin its two deliberate exceptions (credentials and url). Note for external consumers of @launchdarkly/eventsource: the read type of statusText widens to string | undefined, and FetchHeaders.forEach becomes optional, so code that reads these members directly must guard them.

The Shopify Oxygen implementation converts the platform options at its native fetch boundary, because its test configuration declares RequestInit without a global AbortSignal constructor.

No runtime behavior changes beyond the header guard: a transport that supplies no header iteration now reports an empty header set instead of failing the stream as unreadable. This is a deliberate decision, and it follows the existing rule that a 200 response with no Content-Type header is accepted, because a minimal transport can report no headers. The cost is that a transport which forgets forEach loses Content-Type validation on a 200 rather than failing loudly.

This is the bottom of a two-PR stack. #2060 moves the node-family SDKs' streaming transports onto this seam and deletes their parallel fetch adapters.


Note

Overview
Extends the shared platform Requests/Options/Response types so a platform fetch can act as the SSE transport for @launchdarkly/eventsource without a package dependency: optional streaming, signal (AbortSignalLike), response body/BodyReader, optional statusText, and optional Headers.forEach.

On the eventsource side, FetchHeaders.forEach and statusText are optional to match; headersToObject now treats missing forEach as an empty header set (200 streams can open without Content-Type validation). Compile-time checks in typeCompatibility.test.ts lock Requests['fetch'] ↔ FetchLike assignability (with documented exceptions for credentials and url).

Adds internal.toRequestInit and wires Shopify Oxygen to pass platform options through it at native fetch/Request boundaries for AbortSignal typing. New tests cover transports without header iteration or statusText.

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

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

@launchdarkly/js-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 30631 bytes
Compressed size limit: 30000
Uncompressed size: 145908 bytes

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

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

@joker23
joker23 marked this pull request as ready for review October 9, 2026 16:52
@joker23
joker23 requested a review from a team as a code owner October 9, 2026 16:52

@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: No Issues Found

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

Devin Review

@joker23
joker23 marked this pull request as draft October 9, 2026 17:51

This branch has not been deployed

No deployments
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.

1 participant