Skip to content

feat: FlagManager.applyChanges for FDv2 full/partial/none semantics#1208

Merged
kinyoklion merged 7 commits into
mainfrom
rlamb/fdv2-flag-manager-apply-changes
Mar 20, 2026
Merged

feat: FlagManager.applyChanges for FDv2 full/partial/none semantics#1208
kinyoklion merged 7 commits into
mainfrom
rlamb/fdv2-flag-manager-apply-changes

Conversation

@kinyoklion

@kinyoklion kinyoklion commented Mar 19, 2026

Copy link
Copy Markdown
Member

Review 1207 first.

Summary

  • Add applyChanges(context, updates, type) method to FlagManager interface and FlagPersistence
  • 'full': replaces all flags (like init)
  • 'partial': upserts individual flags
  • 'none': persists cache (updating freshness) without changing flags

Stacked on #1207.


Note

Medium Risk
Touches core flag update/caching behavior by adding a new update path that bypasses version and active-context checks, which could affect consistency if misused. Changes are contained and covered by new unit tests, plus a CI-only workflow tweak.

Overview
Adds a new FlagManager.applyChanges(context, updates, type) API (and plumbing through FlagPersistence, FlagUpdater, and FlagStore) to support FDv2 update semantics: full replace, partial merge/upsert without version/active-context guards, and none no-op flag changes while still persisting cache/freshness.

Updates change-event emission to match the new modes (init for full diffs, patch for partial key lists) and adds unit tests covering replacement vs merge behavior, freshness persistence on none, version-check bypass, and change callbacks.

Separately relaxes the browser CI package-size gate by raising the limit from 25000 to 34000.

Written by Cursor Bugbot for commit b5e5dc3. This will update automatically on new commits. Configure here.


Open with Devin

…xtensions

Add InitializerEntry/SynchronizerEntry types for type-safe mode definitions,
refine protocolHandler validation to use isNullish for version/target fields,
add connectionModes config option, split validator arrays for initializers vs
synchronizers, and extend DataManager with optional streaming/flush methods.
Add applyChanges method to FlagManager and FlagPersistence that handles
full replacement, partial upsert, and no-change persistence in a single
call, designed for the FDv2 data path.
Comment thread packages/shared/sdk-client/src/flag-manager/FlagPersistence.ts Outdated
Comment thread packages/shared/sdk-client/src/flag-manager/FlagPersistence.ts Outdated
Comment thread packages/shared/sdk-client/src/flag-manager/FlagPersistence.ts Outdated
Comment thread packages/shared/sdk-client/src/flag-manager/FlagPersistence.ts Outdated
Base automatically changed from rlamb/fdv2-types-and-validators to main March 20, 2026 15:56
Comment thread packages/shared/sdk-client/src/flag-manager/FlagPersistence.ts Outdated
kinyoklion added a commit that referenced this pull request Mar 20, 2026
## Summary

Converts: `{polling: {initializers: ['cache', 'polling'], synchronizers:
['streaming']}}` into real factories.

- Add `SourceFactoryProvider` interface and
`createDefaultSourceFactoryProvider` implementation
- Converts declarative `InitializerEntry`/`SynchronizerEntry` config
into concrete factories and synchronizer slots
- Supports per-entry endpoint overrides (custom polling/streaming URIs)
and interval overrides
- Handles `cache`, `polling`, and `streaming` entry types

Stacked on #1207. Independent of #1208 (FlagManager.applyChanges).


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Introduces a new factory layer that determines how
polling/streaming/cache sources are instantiated (including
endpoint/interval overrides), which can affect connection behavior if
integrated incorrectly. Changes are well-covered by unit tests and are
otherwise additive.
> 
> **Overview**
> Adds a new `SourceFactoryProvider` abstraction (with
`createDefaultSourceFactoryProvider`) that converts declarative
`InitializerEntry`/`SynchronizerEntry` configs into concrete FDv2
initializer factories and synchronizer slots, supporting `cache`,
`polling`, and `streaming` entries.
> 
> Implements per-entry overrides for endpoints and timing (poll interval
and streaming reconnect delay), including ensuring the streaming ping
handler always uses the latest selector and any endpoint-overridden
polling requestor.
> 
> Exports the new provider/types from `sdk-client` public entrypoint and
updates CI package-size thresholds for `js-sdk-common` and
`js-client-sdk-common` to accommodate the added code/tests.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
de39213. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- devin-review-badge-begin -->

---

<a href="https://app.devin.ai/review/launchdarkly/js-core/pull/1209"
target="_blank">
  <picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img
src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
alt="Open with Devin">
  </picture>
</a>
<!-- devin-review-badge-end -->
… checks

Push applyChanges down through the flag manager layers so the FDv2 path
no longer routes through FDv1's upsert (which has version checks and
inactive-context guards). FlagStore.applyPartial inserts without version
comparison, and FlagUpdater.applyChanges sets the active context directly
and emits change events.
…er-apply-changes

# Conflicts:
#	packages/shared/sdk-client/src/datasource/fdv2/FDv2DataSource.ts
@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: 25661 bytes
Compressed size limit: 29000
Uncompressed size: 126143 bytes

@github-actions

github-actions Bot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Mar 20, 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: 29404 bytes
Compressed size limit: 38000
Uncompressed size: 158016 bytes

cursor[bot]

This comment was marked as resolved.

Account for new FDv2 applyChanges code in FlagUpdater/FlagStore that
flows into the browser SDK bundle.
Replace FlagStore.applyPartial with FlagStore.applyChanges that handles
full/partial/none, delegating to init for full. FlagUpdater.applyChanges
now delegates storage to FlagStore.applyChanges and only handles change
event computation.

@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 potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

@kinyoklion kinyoklion merged commit d9a1bd7 into main Mar 20, 2026
46 checks passed
@kinyoklion kinyoklion deleted the rlamb/fdv2-flag-manager-apply-changes branch March 20, 2026 23:04
@github-actions github-actions Bot mentioned this pull request Mar 20, 2026
joker23 pushed a commit that referenced this pull request Mar 23, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>akamai-edgeworker-sdk-common: 2.0.17</summary>

##
[2.0.17](akamai-edgeworker-sdk-common-v2.0.16...akamai-edgeworker-sdk-common-v2.0.17)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @launchdarkly/js-server-sdk-common bumped from ^2.18.2 to ^2.18.3
</details>

<details><summary>akamai-server-base-sdk: 3.0.18</summary>

##
[3.0.18](akamai-server-base-sdk-v3.0.17...akamai-server-base-sdk-v3.0.18)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
* @launchdarkly/akamai-edgeworker-sdk-common bumped from ^2.0.16 to
^2.0.17
    * @launchdarkly/js-server-sdk-common bumped from ^2.18.2 to ^2.18.3
</details>

<details><summary>akamai-server-edgekv-sdk: 1.4.20</summary>

##
[1.4.20](akamai-server-edgekv-sdk-v1.4.19...akamai-server-edgekv-sdk-v1.4.20)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
* @launchdarkly/akamai-edgeworker-sdk-common bumped from ^2.0.16 to
^2.0.17
    * @launchdarkly/js-server-sdk-common bumped from ^2.18.2 to ^2.18.3
</details>

<details><summary>browser: 0.1.13</summary>

##
[0.1.13](browser-v0.1.12...browser-v0.1.13)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @launchdarkly/js-client-sdk bumped from 4.4.0 to 4.4.1
</details>

<details><summary>browser-telemetry: 1.0.29</summary>

##
[1.0.29](browser-telemetry-v1.0.28...browser-telemetry-v1.0.29)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * devDependencies
    * @launchdarkly/js-client-sdk bumped from 4.4.0 to 4.4.1
</details>

<details><summary>cloudflare-server-sdk: 2.7.17</summary>

##
[2.7.17](cloudflare-server-sdk-v2.7.16...cloudflare-server-sdk-v2.7.17)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
* @launchdarkly/js-server-sdk-common-edge bumped from 2.6.15 to 2.6.16
</details>

<details><summary>fastly-server-sdk: 0.2.9</summary>

##
[0.2.9](fastly-server-sdk-v0.2.8...fastly-server-sdk-v0.2.9)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @launchdarkly/js-server-sdk-common bumped from 2.18.2 to 2.18.3
</details>

<details><summary>jest: 1.0.8</summary>

##
[1.0.8](jest-v1.0.7...jest-v1.0.8)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
* @launchdarkly/react-native-client-sdk bumped from ~10.15.0 to ~10.15.1
</details>

<details><summary>js-client-sdk: 4.4.1</summary>

##
[4.4.1](js-client-sdk-v4.4.0...js-client-sdk-v4.4.1)
(2026-03-23)


### Bug Fixes

* Report data source state as valid after bootstrap
([#1203](#1203))
([b00889f](b00889f))


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @launchdarkly/js-client-sdk-common bumped from 1.22.0 to 1.23.0
</details>

<details><summary>js-client-sdk-common: 1.23.0</summary>

##
[1.23.0](js-client-sdk-common-v1.22.0...js-client-sdk-common-v1.23.0)
(2026-03-23)


### Features

* FDv2 types, refined validators, and DataManager interface
([#1207](#1207))
([d7ccfc1](d7ccfc1))
* FlagManager.applyChanges for FDv2 full/partial/none semantics
([#1208](#1208))
([d9a1bd7](d9a1bd7))
* SourceFactoryProvider for declarative data source creation
([#1209](#1209))
([e254f77](e254f77))


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @launchdarkly/js-sdk-common bumped from 2.23.0 to 2.24.0
</details>

<details><summary>js-sdk-common: 2.24.0</summary>

##
[2.24.0](js-sdk-common-v2.23.0...js-sdk-common-v2.24.0)
(2026-03-23)


### Features

* FDv2 types, refined validators, and DataManager interface
([#1207](#1207))
([d7ccfc1](d7ccfc1))
</details>

<details><summary>js-server-sdk-common: 2.18.3</summary>

##
[2.18.3](js-server-sdk-common-v2.18.2...js-server-sdk-common-v2.18.3)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @launchdarkly/js-sdk-common bumped from 2.23.0 to 2.24.0
</details>

<details><summary>js-server-sdk-common-edge: 2.6.16</summary>

##
[2.6.16](js-server-sdk-common-edge-v2.6.15...js-server-sdk-common-edge-v2.6.16)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @launchdarkly/js-server-sdk-common bumped from 2.18.2 to 2.18.3
</details>

<details><summary>node-server-sdk: 9.10.10</summary>

##
[9.10.10](node-server-sdk-v9.10.9...node-server-sdk-v9.10.10)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @launchdarkly/js-server-sdk-common bumped from 2.18.2 to 2.18.3
</details>

<details><summary>node-server-sdk-dynamodb: 6.2.22</summary>

##
[6.2.22](node-server-sdk-dynamodb-v6.2.21...node-server-sdk-dynamodb-v6.2.22)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * devDependencies
    * @launchdarkly/node-server-sdk bumped from 9.10.9 to 9.10.10
  * peerDependencies
    * @launchdarkly/node-server-sdk bumped from >=9.4.3 to >=9.10.10
</details>

<details><summary>node-server-sdk-otel: 1.3.10</summary>

##
[1.3.10](node-server-sdk-otel-v1.3.9...node-server-sdk-otel-v1.3.10)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * devDependencies
    * @launchdarkly/node-server-sdk bumped from 9.10.9 to 9.10.10
  * peerDependencies
    * @launchdarkly/node-server-sdk bumped from >=9.4.3 to >=9.10.10
</details>

<details><summary>node-server-sdk-redis: 4.2.22</summary>

##
[4.2.22](node-server-sdk-redis-v4.2.21...node-server-sdk-redis-v4.2.22)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * devDependencies
    * @launchdarkly/node-server-sdk bumped from 9.10.9 to 9.10.10
  * peerDependencies
    * @launchdarkly/node-server-sdk bumped from >=9.4.3 to >=9.10.10
</details>

<details><summary>react-native-client-sdk: 10.15.1</summary>

##
[10.15.1](react-native-client-sdk-v10.15.0...react-native-client-sdk-v10.15.1)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @launchdarkly/js-client-sdk-common bumped from 1.22.0 to 1.23.0
</details>

<details><summary>react-sdk: 0.1.0</summary>

##
[0.1.0](react-sdk-v0.0.1...react-sdk-v0.1.0)
(2026-03-23)


### Features

* pre-release of `@launchdarkly/react-sdk`
([#1201](#1201))
([69f4790](69f4790))


### Bug Fixes

* **deps:** update dependency next to v16.1.5 [security]
([#1164](#1164))
([929a385](929a385))
* **deps:** update dependency next to v16.1.7 [security]
([#1196](#1196))
([1572be1](1572be1))


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @launchdarkly/js-client-sdk bumped from ^4.4.0 to ^4.4.1
    * @launchdarkly/js-server-sdk-common bumped from ^2.18.2 to ^2.18.3
</details>

<details><summary>server-sdk-ai: 0.16.7</summary>

##
[0.16.7](server-sdk-ai-v0.16.6...server-sdk-ai-v0.16.7)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * devDependencies
    * @launchdarkly/js-server-sdk-common bumped from 2.18.2 to 2.18.3
  * peerDependencies
    * @launchdarkly/js-server-sdk-common bumped from 2.x to 2.18.3
</details>

<details><summary>server-sdk-ai-langchain: 0.5.3</summary>

##
[0.5.3](server-sdk-ai-langchain-v0.5.2...server-sdk-ai-langchain-v0.5.3)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * devDependencies
    * @launchdarkly/server-sdk-ai bumped from ^0.16.6 to ^0.16.7
  * peerDependencies
* @launchdarkly/server-sdk-ai bumped from ^0.15.0 || ^0.16.0 to ^0.16.7
</details>

<details><summary>server-sdk-ai-openai: 0.5.3</summary>

##
[0.5.3](server-sdk-ai-openai-v0.5.2...server-sdk-ai-openai-v0.5.3)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * devDependencies
    * @launchdarkly/js-server-sdk-common bumped from 2.18.2 to 2.18.3
    * @launchdarkly/server-sdk-ai bumped from ^0.16.6 to ^0.16.7
  * peerDependencies
* @launchdarkly/server-sdk-ai bumped from ^0.15.0 || ^0.16.0 to ^0.16.7
</details>

<details><summary>server-sdk-ai-vercel: 0.5.3</summary>

##
[0.5.3](server-sdk-ai-vercel-v0.5.2...server-sdk-ai-vercel-v0.5.3)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * devDependencies
    * @launchdarkly/server-sdk-ai bumped from ^0.16.6 to ^0.16.7
  * peerDependencies
* @launchdarkly/server-sdk-ai bumped from ^0.15.0 || ^0.16.0 to ^0.16.7
</details>

<details><summary>shopify-oxygen-sdk: 0.1.7</summary>

##
[0.1.7](shopify-oxygen-sdk-v0.1.6...shopify-oxygen-sdk-v0.1.7)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
    * @launchdarkly/js-server-sdk-common bumped from 2.18.2 to 2.18.3
</details>

<details><summary>vercel-server-sdk: 1.3.42</summary>

##
[1.3.42](vercel-server-sdk-v1.3.41...vercel-server-sdk-v1.3.42)
(2026-03-23)


### Dependencies

* The following workspace dependencies were updated
  * dependencies
* @launchdarkly/js-server-sdk-common-edge bumped from 2.6.15 to 2.6.16
</details>

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

> [!NOTE]
> **Low Risk**
> Primarily metadata-only release changes (version constants,
`package.json` deps, and `CHANGELOG.md` updates) with minimal functional
code impact. Risk is limited to ensuring version strings and dependency
bumps are consistent across packages.
> 
> **Overview**
> **Automated release PR** that bumps versions across many packages via
release-please and updates `.release-please-manifest.json` accordingly.
> 
> Updates each package’s `package.json` (and a few embedded
`sdkVersion`/`version` constants used for user-agent/platform info) plus
`CHANGELOG.md` entries, and rolls forward internal dependency pins
(notably `@launchdarkly/js-sdk-common` → `2.24.0`,
`@launchdarkly/js-client-sdk-common` → `1.23.0`,
`@launchdarkly/js-server-sdk-common` → `2.18.3`, and the leaf SDKs that
depend on them).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
46e1356. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
kinyoklion added a commit that referenced this pull request Mar 25, 2026
#1210)

## Summary
- Add `FDv2DataManagerBase` — shared data manager orchestrating FDv2
connection mode switching, state debouncing, and data source lifecycle
- Implements `DataManager` interface with foreground/background mode
support, forced/automatic streaming control, and flush callbacks
- Includes `FlagManager.applyChanges` from #1208 for full/partial/none
flag update semantics

Stacked on #1209 and #1208.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds a new shared FDv2 data manager that controls connection-mode
resolution and data source lifecycle, plus updates public `dataSystem`
option shapes; mistakes here could affect SDK initialization,
reconnection behavior, and flag freshness across platforms.
> 
> **Overview**
> Introduces `createFDv2DataManagerBase` (and exported types) as a
shared FDv2 orchestration layer that performs mode
resolution/debouncing, manages `FDv2DataSource` creation/teardown across
identifies and mode changes, tracks selector state, triggers a
background flush callback, and optionally appends a blocked FDv1 polling
fallback synchronizer.
> 
> Updates the public `dataSystem` configuration model by renaming
`initialConnectionMode` to `foregroundConnectionMode` in platform
defaults and by making `automaticModeSwitching` a discriminated union
(`{type:'automatic'}` vs `{type:'manual', initialConnectionMode}`), with
validator support via `validatorOf(..., { is })`; tests are updated and
expanded accordingly, including a large new test suite for
`FDv2DataManagerBase`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0786b64. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- devin-review-badge-begin -->

---

<a href="https://app.devin.ai/review/launchdarkly/js-core/pull/1210"
target="_blank">
  <picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img
src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1"
alt="Open with Devin">
  </picture>
</a>
<!-- devin-review-badge-end -->
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