@@ -14,11 +14,10 @@ import {
1414 Platform ,
1515 ProcessStreamResponse ,
1616 EventName as StreamEventName ,
17- subsystem ,
1817 TypeValidators ,
1918} from '@launchdarkly/js-sdk-common' ;
2019
21- import { LDClient , type LDOptions } from './api' ;
20+ import { ConnectionMode , LDClient , type LDOptions } from './api' ;
2221import LDEmitter , { EventName } from './api/LDEmitter' ;
2322import Configuration from './configuration' ;
2423import createDiagnosticsManager from './diagnostics/createDiagnosticsManager' ;
@@ -34,9 +33,9 @@ export default class LDClientImpl implements LDClient {
3433 config : Configuration ;
3534 context ?: LDContext ;
3635 diagnosticsManager ?: internal . DiagnosticsManager ;
37- eventProcessor : subsystem . LDEventProcessor ;
38- streamer ?: internal . StreamingProcessor ;
36+ eventProcessor ?: internal . EventProcessor ;
3937 logger : LDLogger ;
38+ streamer ?: internal . StreamingProcessor ;
4039
4140 private eventFactoryDefault = new EventFactory ( false ) ;
4241 private eventFactoryWithReasons = new EventFactory ( true ) ;
@@ -74,10 +73,45 @@ export default class LDClientImpl implements LDClient {
7473 this . config ,
7574 platform ,
7675 this . diagnosticsManager ,
76+ ! this . isOffline ( ) ,
7777 ) ;
7878 this . emitter = new LDEmitter ( ) ;
7979 }
8080
81+ async setConnectionMode ( mode : ConnectionMode ) : Promise < void > {
82+ if ( this . config . connectionMode === mode ) {
83+ this . logger . debug ( `setConnectionMode ignored. Mode is already '${ mode } '.` ) ;
84+ return Promise . resolve ( ) ;
85+ }
86+
87+ this . config . connectionMode = mode ;
88+ this . logger . debug ( `setConnectionMode ${ mode } .` ) ;
89+
90+ switch ( mode ) {
91+ case 'offline' :
92+ return this . close ( ) ;
93+ case 'streaming' :
94+ this . eventProcessor ?. start ( ) ;
95+
96+ if ( this . context ) {
97+ // identify will start streamer
98+ return this . identify ( this . context ) ;
99+ }
100+ break ;
101+ default :
102+ this . logger . warn (
103+ `Unknown ConnectionMode: ${ mode } . Only 'offline' and 'streaming' are supported.` ,
104+ ) ;
105+ break ;
106+ }
107+
108+ return Promise . resolve ( ) ;
109+ }
110+
111+ isOffline ( ) {
112+ return this . config . connectionMode === 'offline' ;
113+ }
114+
81115 allFlags ( ) : LDFlagSet {
82116 const result : LDFlagSet = { } ;
83117 Object . entries ( this . flags ) . forEach ( ( [ k , r ] ) => {
@@ -90,16 +124,20 @@ export default class LDClientImpl implements LDClient {
90124
91125 async close ( ) : Promise < void > {
92126 await this . flush ( ) ;
93- this . eventProcessor . close ( ) ;
127+ this . eventProcessor ? .close ( ) ;
94128 this . streamer ?. close ( ) ;
129+ this . logger . debug ( 'Closed eventProcessor and streamer.' ) ;
95130 }
96131
97132 async flush ( ) : Promise < { error ?: Error ; result : boolean } > {
98133 try {
99- await this . eventProcessor . flush ( ) ;
134+ await this . eventProcessor ?. flush ( ) ;
135+ this . logger . debug ( 'Successfully flushed eventProcessor.' ) ;
100136 } catch ( e ) {
137+ this . logger . error ( `Error flushing eventProcessor: ${ e } .` ) ;
101138 return { error : e as Error , result : false } ;
102139 }
140+
103141 return { result : true } ;
104142 }
105143
@@ -232,7 +270,6 @@ export default class LDClientImpl implements LDClient {
232270 return f ? JSON . parse ( f ) : undefined ;
233271 }
234272
235- // TODO: implement secure mode
236273 async identify ( pristineContext : LDContext , _hash ?: string ) : Promise < void > {
237274 let context = await ensureKey ( pristineContext , this . platform ) ;
238275
@@ -262,19 +299,30 @@ export default class LDClientImpl implements LDClient {
262299 this . emitter . emit ( 'change' , context , changedKeys ) ;
263300 }
264301
265- this . streamer ?. close ( ) ;
266- this . streamer = new internal . StreamingProcessor (
267- this . sdkKey ,
268- this . clientContext ,
269- this . createStreamUriPath ( context ) ,
270- this . createStreamListeners ( context , checkedContext . canonicalKey , identifyResolve ) ,
271- this . diagnosticsManager ,
272- ( e ) => {
273- this . logger . error ( e ) ;
274- this . emitter . emit ( 'error' , context , e ) ;
275- } ,
276- ) ;
277- this . streamer . start ( ) ;
302+ if ( this . isOffline ( ) ) {
303+ if ( flagsStorage ) {
304+ this . logger . debug ( 'Offline identify using storage flags.' ) ;
305+ } else {
306+ this . logger . debug ( 'Offline identify no storage. Defaults will be used.' ) ;
307+ this . context = context ;
308+ this . flags = { } ;
309+ identifyResolve ( ) ;
310+ }
311+ } else {
312+ this . streamer ?. close ( ) ;
313+ this . streamer = new internal . StreamingProcessor (
314+ this . sdkKey ,
315+ this . clientContext ,
316+ this . createStreamUriPath ( context ) ,
317+ this . createStreamListeners ( context , checkedContext . canonicalKey , identifyResolve ) ,
318+ this . diagnosticsManager ,
319+ ( e ) => {
320+ this . logger . error ( e ) ;
321+ this . emitter . emit ( 'error' , context , e ) ;
322+ } ,
323+ ) ;
324+ this . streamer . start ( ) ;
325+ }
278326
279327 return identifyPromise ;
280328 }
@@ -298,13 +346,11 @@ export default class LDClientImpl implements LDClient {
298346 return ;
299347 }
300348
301- this . eventProcessor . sendEvent (
349+ this . eventProcessor ? .sendEvent (
302350 this . eventFactoryDefault . customEvent ( key , checkedContext ! , data , metricValue ) ,
303351 ) ;
304352 }
305353
306- // TODO: move variation functions to a separate file to make this file size
307- // more manageable.
308354 private variationInternal (
309355 flagKey : string ,
310356 defaultValue : any ,
@@ -322,11 +368,11 @@ export default class LDClientImpl implements LDClient {
322368 if ( ! found || found . deleted ) {
323369 const defVal = defaultValue ?? null ;
324370 const error = new LDClientError (
325- `Unknown feature flag "${ flagKey } "; returning default value ${ defVal } ` ,
371+ `Unknown feature flag "${ flagKey } "; returning default value ${ defVal } . ` ,
326372 ) ;
327373 this . logger . error ( error ) ;
328374 this . emitter . emit ( 'error' , this . context , error ) ;
329- this . eventProcessor . sendEvent (
375+ this . eventProcessor ? .sendEvent (
330376 this . eventFactoryDefault . unknownFlagEvent ( flagKey , defVal , evalContext ) ,
331377 ) ;
332378 return createErrorEvaluationDetail ( ErrorKinds . FlagNotFound , defaultValue ) ;
@@ -337,7 +383,7 @@ export default class LDClientImpl implements LDClient {
337383 if ( typeChecker ) {
338384 const [ matched , type ] = typeChecker ( value ) ;
339385 if ( ! matched ) {
340- this . eventProcessor . sendEvent (
386+ this . eventProcessor ? .sendEvent (
341387 eventFactory . evalEventClient (
342388 flagKey ,
343389 defaultValue , // track default value on type errors
@@ -361,7 +407,7 @@ export default class LDClientImpl implements LDClient {
361407 this . logger . debug ( 'Result value is null in variation' ) ;
362408 successDetail . value = defaultValue ;
363409 }
364- this . eventProcessor . sendEvent (
410+ this . eventProcessor ? .sendEvent (
365411 eventFactory . evalEventClient ( flagKey , value , defaultValue , found , evalContext , reason ) ,
366412 ) ;
367413 return successDetail ;
0 commit comments