feat: Wire FDv2 connection-mode resolution in flutter SDK#280
Conversation
Wires the FDv2 mode-resolution scaffolding (merged via #274) into the common_client runtime path while keeping the FDv1 ConnectionMode enum and all existing public API signatures unchanged. LDCommonClient: - setMode(ConnectionMode) keeps its FDv1 signature and now maps the 3 legacy modes to ResolvedConnectionMode internally before forwarding to DataSourceManager. - New setResolvedMode(ResolvedConnectionMode) is the advanced FDv2 entry point. Documented as EAP / not-stable. No internal caller in this PR; the Flutter SDK's ConnectionManager invokes it in the follow-up flutter PR. - DataSourceFactoriesFn (the public, optional constructor seam) remains typed Map<ConnectionMode, DataSourceFactory> so external callers can still customize streaming + polling. _backgroundFactory is SDK-managed (background is FDv2-only), and _composeFactoriesForManager translates the FDv1 map into the FDv2-keyed Map<FDv2ConnectionMode, DataSourceFactory> consumed by DataSourceManager. DataSourceManager (internal, not publicly exported): - Active mode held as ResolvedConnectionMode. - Factory map is keyed by FDv2ConnectionMode. - ResolvedOffline branches dispatch status as setOffline / networkUnavailable / backgroundDisabled depending on OfflineDetail. Tests updated to match.
Wires the FDv2 mode-resolution machinery (from common_client) into the Flutter SDK's ConnectionManager while preserving all existing public API signatures. ConnectionManager: - DartClientAdapter forwards ResolvedConnectionMode to LDCommonClient.setResolvedMode (the new advanced FDv2 entry point). - ConnectionManagerConfig.backgroundConnectionMode (new) is typed FDv2ConnectionMode; initialConnectionMode stays ConnectionMode (legacy). - disableAutomaticBackgroundHandling keeps its original name. - Automatic mode resolution uses resolveMode + flutterDefaultResolutionTable; setMode override path supports the 3 FDv1 modes only (background is auto-resolved, not user-selectable). Flutter umbrella re-exports cover the FDv2 types consumed by this PR (FDv2 connection-mode subtypes, ResolvedConnectionMode family, OfflineDetail family, ModeState/ModeResolutionEntry/resolveMode/ flutterDefaultResolutionTable). Platform defaults (io_config / js_config / stub_config / flutter_default_config) return FDv2ConnectionMode for the background slot. LDClient passes backgroundConnectionMode to the ConnectionManager and sets offline=true post-construction (no longer forces initial mode to offline in config). Tests updated to match. Depends on the LDCommonClient.setResolvedMode addition in the predecessor common-only PR.
Splits the active mode and offline detail into two fields: - _activeConnectionMode: FDv2ConnectionMode -- drives factory lookup (matches the factory map's key type directly). - _offlineDetail: OfflineDetail -- semantically meaningful only when _activeConnectionMode is FDv2Offline; carries a stale value in other modes and is intentionally only read inside the FDv2Offline arm of _setupConnection. ResolvedConnectionMode is now a true boundary type: consumed by setMode, decomposed into the two fields, then discarded. This removes the .connectionMode getter call previously needed for factory lookup. setMode dedup is rewritten to compare the FDv2 mode and (when offline) the offline detail explicitly, so a redundant call with the same effective state still short-circuits. Constructor initializes _offlineDetail to OfflineSetOffline() as a placeholder; it is overwritten the next time setMode receives a ResolvedOffline value.
… ta/SDK-2187/connection-mode-and-resolution-flutter
| /// The initial connection mode the SDK should use. | ||
| /// Configured foreground connection mode used as the automatic resolution | ||
| /// foreground slot. | ||
| final ConnectionMode initialConnectionMode; |
There was a problem hiding this comment.
This is ok if initialConnectionMode is never expected to be background. The asymmetry between initialConnectionMode and backgroundConnectionMode isn't great, but it would require a breaking change to make them symmetric. Thoughts?
There was a problem hiding this comment.
As long as when you disable handling for lifecycle and network we use this mode.
I don't see symmetry as a consideration, but that it can do the things you need it to do.
Is this just a change in comment, or is there a functionality change here as well?
The runtime mode-override path now uses FDv2ConnectionMode end-to-end: - ConnectionManager._modeOverride is FDv2ConnectionMode? (was ConnectionMode?). - ConnectionManager.setMode signature accepts FDv2ConnectionMode? so callers can request any FDv2 mode -- including FDv2Background() -- as the override. - _handleState pattern-matches the four FDv2 subtypes when applying the override. initialConnectionMode stays ConnectionMode (FDv1) because it is bound to LDConfig.dataSourceConfig.initialConnectionMode, an existing user-visible configuration field. The _fdv2FromFdv1 helper retains its remaining caller (translating initialConnectionMode into the ModeState slot). Tests updated. The override iteration in 'given requested connection modes' now exercises all four FDv2 modes (background included).
… ta/SDK-2187/connection-mode-and-resolution-flutter
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ 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 4418f37. Configure here.
The FDv2 connection-mode resolution wiring on this branch consumes APIs introduced in launchdarkly_common_client 1.10.0 (FDv2ConnectionMode + subtypes, ResolvedConnectionMode family) and 1.11.0 (LDCommonClient.setResolvedMode). Bump the pinned exact version to match so published flutter_client_sdk releases resolve against a common_client that actually has these symbols.
🤖 I have created a release *beep* *boop* --- ## [1.12.0](launchdarkly_common_client-v1.11.0...launchdarkly_common_client-v1.12.0) (2026-06-04) ### Features * Wire FDv2 connection-mode resolution in flutter SDK ([#280](#280)) ([ef8ad39](ef8ad39)) --- 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** > Version and changelog-only release with no code diffs in this PR. > > **Overview** > Release Please bumps **`launchdarkly_common_client`** from **1.11.0** to **1.12.0** with matching updates to `.release-please-manifest.json` and `packages/common_client/pubspec.yaml`. > > The new **1.12.0** changelog section documents FDv2 connection-mode resolution wired through the Flutter SDK ([#280]); this PR does not include application or library source changes—only version and release notes. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 54d95d7. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
🤖 I have created a release *beep* *boop* --- ## [4.17.0](4.16.0...4.17.0) (2026-06-04) ### Features * Wire FDv2 connection-mode resolution in flutter SDK ([#280](#280)) ([ef8ad39](ef8ad39)) --- 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** > Version and changelog-only changes from Release Please; no new runtime logic in this diff. > > **Overview** > **Release 4.17.0** for `launchdarkly_flutter_client_sdk`: bumps the package and example app from **4.16.0 → 4.17.0**, updates `.release-please-manifest.json`, and sets the reported `sdkVersion` in `ld_client.dart`. > > The changelog entry records the shipped feature from [#280](#280): **FDv2 connection-mode resolution** wired through the Flutter SDK (no additional implementation changes appear in this diff). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit cd9dc43. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->

Summary
Wires the FDv2 mode-resolution machinery into the Flutter SDK's
ConnectionManager. Stacked on the common_client PR (#279); rebase ontomainonce that merges.This is the second half of the further split of the original behavior PR (#275, now closed).
ConnectionManager
DartClientAdapterforwardsResolvedConnectionModetoLDCommonClient.setResolvedMode(the new advanced FDv2 entry point from feat: Wire FDv2 connection-mode resolution in common_client #279).ConnectionManagerConfig.backgroundConnectionMode(new) is typedFDv2ConnectionMode.initialConnectionModestaysConnectionMode(legacy).disableAutomaticBackgroundHandlingkeeps its original name.resolveMode+flutterDefaultResolutionTable;setModeoverride path supports the 3 FDv1 modes only (background is auto-resolved, not user-selectable).Flutter umbrella re-exports cover the FDv2 types consumed by this PR (
FDv2ConnectionMode+ four subtypes,ResolvedConnectionModefamily,OfflineDetailfamily,ModeState/ModeResolutionEntry/resolveMode/flutterDefaultResolutionTable).Platform defaults (
io_config/js_config/stub_config/flutter_default_config) returnFDv2ConnectionModefor the background slot.LDClient passes
backgroundConnectionModeto theConnectionManagerand setsoffline=truepost-construction (no longer forces initial mode to offline in config).Tests updated to match.
Depends on #279 -- the
LDCommonClient.setResolvedModemethod this PR consumes lives there.Note
Medium Risk
Connection and data-source behavior changes across foreground/background and network transitions (including new status reasons and mobile background polling), which can affect flag freshness and event delivery even though public FDv1
setModeremains.Overview
Flutter
ConnectionManagernow picks aResolvedConnectionModefrom app foreground/background, network, config, and optional overrides usingresolveModeandflutterDefaultResolutionTable(custom tables supported). It forwards modes throughDartClientAdapter.setResolvedMode, addsbackgroundConnectionMode, andsetMode(FDv2ConnectionMode?)for manual override. Background transitions still flush events; event sending rules are tied to offline / background +runInBackground.common_clientDataSourceManageris keyed onFDv2ConnectionModefactories andsetMode(ResolvedConnectionMode), mapping offlineOfflineDetailtosetOffline/setNetworkUnavailable/setBackgroundDisabled.LDCommonClientcomposes FDv1 factories into FDv2 (including an SDK-managed background polling factory), exposessetResolvedMode, and stops pushing network availability into the data source manager (Flutter resolves network loss toResolvedOffline(OfflineNetworkUnavailable)instead).Platform defaults: mobile uses
FDv2Backgroundand enables automatic background/network handling by default; desktop and web default the background slot to offline and disable those detectors unless configured.LDClientpasses the platform background slot and setsConnectionManager.offlineafter build whenconfig.offline. FDv2 types are re-exported from the Flutter package;launchdarkly_common_clientis bumped to 1.11.0.Reviewed by Cursor Bugbot for commit bc0a1ac. Bugbot is set up for automated code reviews on this repo. Configure here.