Skip to content

feat: [FD-5562] Adding FDv2 Stream endpoint support in the dev server - #703

Merged
hkotian merged 3 commits into
mainfrom
hkotian/FD-5562/v2-stream-support
May 4, 2026
Merged

hkotian merged 3 commits into
mainfrom
hkotian/FD-5562/v2-stream-support

Conversation

@hkotian

@hkotian hkotian commented Apr 29, 2026 •

Copy link
Copy Markdown
Contributor

Requirements

  • I have added test coverage for new or changed functionality
  • I have followed the repository's pull request submission guidelines
  • I have validated my changes against all supported platform versions

Related issues

Provide links to any issues in this repository or elsewhere relating to this pull request.

Describe the solution you've provided

Piggy backing from the polling fdv2 support, in this PR we are introducing the FDv2 streaming endpoint support.
Like polling endpoints, the initial transfer would either be

  1. No-transfer: If there is no change in the payload
  2. Or full transfer: Otherwise

An override or sync would also send stream updated in the FDv2 format, as expected.

On a sync the updates will look as follows

event:server-intent
data:{"payloads":[{"id":"fw-test-project","target":15,"intentCode":"xfer-full","reason":"cant-catchup"}]}

event:put-object
data:{"version":15,"kind":"flag","key":"update-flag-4","object":{"key":"update-flag-4","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":[false],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":107,"deleted":false}}

event:put-object
data:{"version":15,"kind":"flag","key":"test-flag-22","object":{"key":"test-flag-22","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":[false],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":6,"deleted":false}}

event:put-object
data:{"version":15,"kind":"flag","key":"flag-2","object":{"key":"flag-2","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":["B"],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":2,"deleted":false}}

event:put-object
data:{"version":15,"kind":"flag","key":"flag-A","object":{"key":"flag-A","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":["B"],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":7,"deleted":false}}

event:put-object
data:{"version":15,"kind":"flag","key":"bool-flag","object":{"key":"bool-flag","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":[false],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":10,"deleted":false}}

event:put-object
data:{"version":15,"kind":"flag","key":"pre-req","object":{"key":"pre-req","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":[false],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":2,"deleted":false}}

event:put-object
data:{"version":15,"kind":"flag","key":"update-flag-0","object":{"key":"update-flag-0","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":[false],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":107,"deleted":false}}

event:put-object
data:{"version":15,"kind":"flag","key":"update-flag-1","object":{"key":"update-flag-1","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":[false],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":107,"deleted":false}}

event:put-object
data:{"version":15,"kind":"flag","key":"pre-req-with-string","object":{"key":"pre-req-with-string","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":["second"],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":2,"deleted":false}}

event:put-object
data:{"version":15,"kind":"flag","key":"update-flag-3","object":{"key":"update-flag-3","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":[false],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":107,"deleted":false}}

event:put-object
data:{"version":15,"kind":"flag","key":"update-flag-2","object":{"key":"update-flag-2","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":[false],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":107,"deleted":false}}

event:put-object
data:{"version":15,"kind":"flag","key":"flag-3","object":{"key":"flag-3","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":["B"],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":false,"trackEventsFallthrough":false,"debugEventsUntilDate":0,"version":2,"deleted":false}}

event:payload-transferred
data:{"state":"(p:fw-test-project:15)","version":15}

Whereas a single override will emit a single event :

event:server-intent
data:{"payloads":[{"id":"fw-test-project","target":16,"intentCode":"xfer-changes","reason":"update"}]}

event:put-object
data:{"version":16,"kind":"flag","key":"bool-flag","object":{"key":"bool-flag","on":true,"prerequisites":[],"targets":[],"rules":[],"fallthrough":{"variation":0},"offVariation":0,"variations":[true],"clientSideAvailability":{"usingMobileKey":true,"usingEnvironmentId":true},"clientSide":true,"salt":"","trackEvents":true,"trackEventsFallthrough":true,"debugEventsUntilDate":0,"version":11,"deleted":false}}

event:payload-transferred
data:{"state":"(p:fw-test-project:16)","version":16}

Describe alternatives you've considered

Provide a clear and concise description of any alternative solutions or features you've considered.

Additional context

Add any other context about the pull request here.


Note

Medium Risk
Touches core streaming infrastructure and event payload shapes; mistakes could break SSE clients or cause versioning inconsistencies across polling/streaming updates.

Overview
Adds a new /sdk/stream endpoint that serves Flag Delivery v2 over SSE: it sends an initial FDv2 response based on basis, then pushes incremental flag updates (xfer-changes + put-object + payload-transferred) on overrides and full retransfers on project sync.

To support streaming updates, OverrideEvent and SyncEvent now carry PayloadVersion (propagated from IncrementProjectPayloadVersion), and the generic SSE plumbing is refactored so OpenStream/observers write raw []byte payloads (with Message.ToPayload() used by non-FDv2 streams).

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


Related Jira issue: FD-5562: Implement server side streaming endpoint handling in Launchdarkly dev server

@launchdarkly-upra launchdarkly-upra Bot changed the title Adding FDv2 Stream endpoint support in the dev server [FD-5562] Adding FDv2 Stream endpoint support in the dev server Apr 29, 2026
@hkotian hkotian changed the title [FD-5562] Adding FDv2 Stream endpoint support in the dev server [FD-5562] feat: Adding FDv2 Stream endpoint support in the dev server Apr 30, 2026
@hkotian hkotian changed the title [FD-5562] feat: Adding FDv2 Stream endpoint support in the dev server feat: [FD-5562] Adding FDv2 Stream endpoint support in the dev server Apr 30, 2026
@hkotian
hkotian marked this pull request as ready for review April 30, 2026 02:23
@hkotian
hkotian requested review from a team, colincstuart, cspath1, keelerm84, kinyoklion, nieblara, singhshalinis01 and svenkatesan-ld and removed request for a team April 30, 2026 02:23

@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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1f4132f. Configure here.

@hkotian
hkotian merged commit ff8c116 into main May 4, 2026
13 checks passed
@hkotian
hkotian deleted the hkotian/FD-5562/v2-stream-support branch May 4, 2026 16:50
social4hyq pushed a commit to social4hyq/homebrew-core that referenced this pull request Sep 20, 2026
ldcli 3.1.0

Created-by: HarmonybrewBot
Commit-by: HarmonybrewBot
Merged-by: HarmonybrewBot
Description: Created by `brew bump`

---

Created with `brew bump-formula-pr`.<details>
  <summary>release notes</summary>
  <pre>## [3.1.0](launchdarkly/ldcli@v3.0.4...v3.1.0) (2026-07-10)


### Features

* [FD-5561] implement FDv2 polling endpoint GET /sdk/poll ([#701](launchdarkly/ldcli#701)) ([8a1cda1](launchdarkly/ldcli@8a1cda1))
* [FD-5562] Adding FDv2 Stream endpoint support in the dev server ([#703](launchdarkly/ldcli#703)) ([ff8c116](launchdarkly/ldcli@ff8c116))
* add whoami command ([#657](launchdarkly/ldcli#657)) ([d2cca65](launchdarkly/ldcli@d2cca65))
* support React Native sourcemaps in sourcemaps upload ([#735](launchdarkly/ldcli#735)) ([e41a87f](launchdarkly/ldcli@e41a87f))


### Bug Fixes

* prevent subcommands from showing root-level commands in help output ([#730](launchdarkly/ldcli#730)) ([ca49101](launchdarkly/ldcli@ca49101))
* **REL-13522:** convert kebab-case query params to camelCase ([#705](launchdarkly/ldcli#705)) ([98700e4](launchdarkly/ldcli@98700e4))
* update install-hooks target to use pre-commit install ([#731](launchdarkly/ldcli#731)) ([424147f](launchdarkly/ldcli@424147f))

---
This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).

<!-- CURSOR_SUMMARY --></pre>
  <p>View the full release notes at <a href="https://github.com/launchdarkly/ldcli/releases/tag/v3.1.0">https://github.com/launchdarkly/ldcli/releases/tag/v3.1.0</a>.</p>
</details>
<hr>

See merge request: Harmonybrew/homebrew-core!14012
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.

3 participants