@@ -4,6 +4,10 @@ import {
44 BasicLogger ,
55 type Configuration ,
66 ConnectionMode ,
7+ createDefaultSourceFactoryProvider ,
8+ createFDv2DataManagerBase ,
9+ FDv2ConnectionMode ,
10+ type FDv2DataManagerControl ,
711 FlagManager ,
812 internal ,
913 LDClientImpl ,
@@ -12,13 +16,21 @@ import {
1216 LDHeaders ,
1317 LDPluginEnvironmentMetadata ,
1418 MOBILE_DATA_SYSTEM_DEFAULTS ,
19+ MOBILE_TRANSITION_TABLE ,
1520 mobileFdv1Endpoints ,
21+ MODE_TABLE ,
22+ resolveForegroundMode ,
1623} from '@launchdarkly/js-client-sdk-common' ;
1724
1825import MobileDataManager from './MobileDataManager' ;
1926import validateOptions , { filterToBaseOptions } from './options' ;
2027import createPlatform from './platform' ;
21- import { ConnectionDestination , ConnectionManager } from './platform/ConnectionManager' ;
28+ import {
29+ ApplicationState ,
30+ ConnectionDestination ,
31+ ConnectionManager ,
32+ NetworkState ,
33+ } from './platform/ConnectionManager' ;
2234import LDOptions from './RNOptions' ;
2335import RNStateDetector from './RNStateDetector' ;
2436
@@ -36,7 +48,8 @@ import RNStateDetector from './RNStateDetector';
3648 * ```
3749 */
3850export default class ReactNativeLDClient extends LDClientImpl {
39- private _connectionManager : ConnectionManager ;
51+ private _connectionManager ?: ConnectionManager ;
52+ private _stateDetector ?: RNStateDetector ;
4053 /**
4154 * Creates an instance of the LaunchDarkly client.
4255 *
@@ -72,62 +85,114 @@ export default class ReactNativeLDClient extends LDClientImpl {
7285 const platform = createPlatform ( logger , options , validatedRnOptions . storage ) ;
7386 const endpoints = mobileFdv1Endpoints ( ) ;
7487
88+ const dataManagerFactory = (
89+ flagManager : FlagManager ,
90+ configuration : Configuration ,
91+ baseHeaders : LDHeaders ,
92+ emitter : LDEmitter ,
93+ diagnosticsManager ?: internal . DiagnosticsManager ,
94+ ) => {
95+ if ( configuration . dataSystem ) {
96+ return createFDv2DataManagerBase ( {
97+ platform,
98+ flagManager,
99+ credential : sdkKey ,
100+ config : configuration ,
101+ baseHeaders,
102+ emitter,
103+ transitionTable : MOBILE_TRANSITION_TABLE ,
104+ foregroundMode : resolveForegroundMode (
105+ configuration . dataSystem ,
106+ MOBILE_DATA_SYSTEM_DEFAULTS ,
107+ ) ,
108+ backgroundMode : configuration . dataSystem . backgroundConnectionMode ?? 'background' ,
109+ modeTable : MODE_TABLE ,
110+ sourceFactoryProvider : createDefaultSourceFactoryProvider ( ) ,
111+ fdv1Endpoints : mobileFdv1Endpoints ( ) ,
112+ buildQueryParams : ( ) => [ ] , // Mobile uses Authorization header, not query params
113+ } ) ;
114+ }
115+
116+ return new MobileDataManager (
117+ platform ,
118+ flagManager ,
119+ sdkKey ,
120+ configuration ,
121+ validatedRnOptions ,
122+ endpoints . polling ,
123+ endpoints . streaming ,
124+ baseHeaders ,
125+ emitter ,
126+ diagnosticsManager ,
127+ ) ;
128+ } ;
129+
75130 super (
76131 sdkKey ,
77132 autoEnvAttributes ,
78133 platform ,
79134 { ...filterToBaseOptions ( options ) , logger } ,
80- (
81- flagManager : FlagManager ,
82- configuration : Configuration ,
83- baseHeaders : LDHeaders ,
84- emitter : LDEmitter ,
85- diagnosticsManager ?: internal . DiagnosticsManager ,
86- ) =>
87- new MobileDataManager (
88- platform ,
89- flagManager ,
90- sdkKey ,
91- configuration ,
92- validatedRnOptions ,
93- endpoints . polling ,
94- endpoints . streaming ,
95- baseHeaders ,
96- emitter ,
97- diagnosticsManager ,
98- ) ,
135+ dataManagerFactory ,
99136 internalOptions ,
100137 ) ;
101138
102- this . setEventSendingEnabled ( ! this . isOffline ( ) , false ) ;
103-
104- const dataManager = this . dataManager as MobileDataManager ;
105- const destination : ConnectionDestination = {
106- setNetworkAvailability : ( available : boolean ) => {
107- dataManager . setNetworkAvailability ( available ) ;
108- } ,
109- setEventSendingEnabled : ( enabled : boolean , flush : boolean ) => {
110- this . setEventSendingEnabled ( enabled , flush ) ;
111- } ,
112- setConnectionMode : async ( mode : ConnectionMode ) => {
113- // Pass the connection mode to the base implementation.
114- // The RN implementation will pass the connection mode through the connection manager.
115- dataManager . setConnectionMode ( mode ) ;
116- } ,
117- } ;
139+ const isFDv2 = ! ! options . dataSystem ;
140+
141+ if ( isFDv2 ) {
142+ const fdv2DataManager = this . dataManager as FDv2DataManagerControl ;
143+
144+ this . setEventSendingEnabled ( true , false ) ;
145+ fdv2DataManager . setFlushCallback ( ( ) => this . flush ( ) ) ;
146+
147+ // Wire state detection directly to FDv2 data manager.
148+ const stateDetector = new RNStateDetector ( ) ;
149+ this . _stateDetector = stateDetector ;
150+
151+ if ( validatedRnOptions . automaticBackgroundHandling ) {
152+ stateDetector . setApplicationStateListener ( ( state ) => {
153+ fdv2DataManager . setLifecycleState (
154+ state === ApplicationState . Foreground ? 'foreground' : 'background' ,
155+ ) ;
156+ } ) ;
157+ }
158+
159+ if ( validatedRnOptions . automaticNetworkHandling ) {
160+ stateDetector . setNetworkStateListener ( ( state ) => {
161+ fdv2DataManager . setNetworkState (
162+ state === NetworkState . Available ? 'available' : 'unavailable' ,
163+ ) ;
164+ } ) ;
165+ }
166+ } else {
167+ const initialConnectionMode = options . initialConnectionMode ?? 'streaming' ;
168+ this . setEventSendingEnabled ( initialConnectionMode !== 'offline' , false ) ;
169+
170+ const dataManager = this . dataManager as MobileDataManager ;
171+ const destination : ConnectionDestination = {
172+ setNetworkAvailability : ( available : boolean ) => {
173+ dataManager . setNetworkAvailability ( available ) ;
174+ } ,
175+ setEventSendingEnabled : ( enabled : boolean , flush : boolean ) => {
176+ this . setEventSendingEnabled ( enabled , flush ) ;
177+ } ,
178+ setConnectionMode : async ( mode : ConnectionMode ) => {
179+ dataManager . setConnectionMode ( mode ) ;
180+ } ,
181+ } ;
182+
183+ this . _connectionManager = new ConnectionManager (
184+ logger ,
185+ {
186+ initialConnectionMode,
187+ automaticNetworkHandling : validatedRnOptions . automaticNetworkHandling ,
188+ automaticBackgroundHandling : validatedRnOptions . automaticBackgroundHandling ,
189+ runInBackground : validatedRnOptions . runInBackground ,
190+ } ,
191+ destination ,
192+ new RNStateDetector ( ) ,
193+ ) ;
194+ }
118195
119- const initialConnectionMode = options . initialConnectionMode ?? 'streaming' ;
120- this . _connectionManager = new ConnectionManager (
121- logger ,
122- {
123- initialConnectionMode,
124- automaticNetworkHandling : validatedRnOptions . automaticNetworkHandling ,
125- automaticBackgroundHandling : validatedRnOptions . automaticBackgroundHandling ,
126- runInBackground : validatedRnOptions . runInBackground ,
127- } ,
128- destination ,
129- new RNStateDetector ( ) ,
130- ) ;
131196 internal . safeRegisterPlugins (
132197 logger ,
133198 this . environmentMetadata ,
@@ -136,24 +201,66 @@ export default class ReactNativeLDClient extends LDClientImpl {
136201 ) ;
137202 }
138203
139- async setConnectionMode ( mode : ConnectionMode ) : Promise < void > {
140- // Set the connection mode before setting offline, in case there is any mode transition work
141- // such as flushing on entering the background.
142- this . _connectionManager . setConnectionMode ( mode ) ;
143- // For now the data source connection and the event processing state are connected.
144- this . _connectionManager . setOffline ( mode === 'offline' ) ;
204+ /**
205+ * @internal
206+ *
207+ * This feature is experimental and should NOT be considered ready for
208+ * production use. It may change or be removed without notice and is not
209+ * subject to backwards compatibility guarantees.
210+ *
211+ * Sets the connection mode for the SDK's data system.
212+ *
213+ * When the FDv2 data system is enabled (`dataSystem` option), this method
214+ * accepts FDv2 connection modes (`'streaming'`, `'polling'`, `'offline'`,
215+ * `'one-shot'`, `'background'`). Pass `undefined` to clear an explicit
216+ * override and return to automatic mode selection.
217+ *
218+ * Without FDv2, this method accepts FDv1 connection modes
219+ * (`'streaming'`, `'polling'`, `'offline'`).
220+ *
221+ * @param mode The connection mode to use, or `undefined` to clear the
222+ * override (FDv2 only).
223+ */
224+ async setConnectionMode ( mode ?: ConnectionMode | FDv2ConnectionMode ) : Promise < void > {
225+ if ( this . _connectionManager ) {
226+ // FDv1 path
227+ if ( mode === undefined || mode === 'one-shot' || mode === 'background' ) {
228+ this . logger . warn (
229+ `setConnectionMode('${ mode } ') is only supported with the FDv2 data system (dataSystem option).` ,
230+ ) ;
231+ return ;
232+ }
233+ this . _connectionManager . setConnectionMode ( mode as ConnectionMode ) ;
234+ this . _connectionManager . setOffline ( mode === 'offline' ) ;
235+ } else {
236+ // FDv2 path
237+ if ( mode !== undefined && ! ( mode in MODE_TABLE ) ) {
238+ this . logger . warn (
239+ `setConnectionMode called with invalid mode '${ mode } '. ` +
240+ `Valid modes: ${ Object . keys ( MODE_TABLE ) . join ( ', ' ) } .` ,
241+ ) ;
242+ return ;
243+ }
244+ ( this . dataManager as FDv2DataManagerControl ) . setConnectionMode (
245+ mode as FDv2ConnectionMode | undefined ,
246+ ) ;
247+ }
145248 }
146249
147250 /**
148251 * Gets the SDK connection mode.
149252 */
150- getConnectionMode ( ) : ConnectionMode {
151- const dataManager = this . dataManager as MobileDataManager ;
152- return dataManager . getConnectionMode ( ) ;
253+ getConnectionMode ( ) : ConnectionMode | FDv2ConnectionMode {
254+ if ( this . _connectionManager ) {
255+ return ( this . dataManager as MobileDataManager ) . getConnectionMode ( ) ;
256+ }
257+ return ( this . dataManager as FDv2DataManagerControl ) . getCurrentMode ( ) ;
153258 }
154259
155260 isOffline ( ) {
156- const dataManager = this . dataManager as MobileDataManager ;
157- return dataManager . getConnectionMode ( ) === 'offline' ;
261+ if ( this . _connectionManager ) {
262+ return ( this . dataManager as MobileDataManager ) . getConnectionMode ( ) === 'offline' ;
263+ }
264+ return ( this . dataManager as FDv2DataManagerControl ) . getCurrentMode ( ) === 'offline' ;
158265 }
159266}
0 commit comments