@@ -26,7 +26,7 @@ import {
2626import { evaluate } from '../evaluation'
2727import { createExposureLoggingHook } from './exposures'
2828import { createFlagEvalEVPHook } from './flagEvaluations'
29- import { createRumTrackingHook } from './rumIntegration'
29+ import { createRumTrackingHook , enrichEvaluationContextWithRumUser } from './rumIntegration'
3030
3131/**
3232 * @deprecated Use FlaggingInitConfiguration instead
@@ -64,6 +64,18 @@ export class DatadogProvider implements Provider {
6464 /** Provider-level configuration */
6565 private readonly configuration ?: FlaggingConfiguration
6666
67+ /** Controls both directions of the provider's RUM integration. */
68+ private readonly isRumIntegrationEnabled : boolean
69+
70+ // TODO: Migrate this manual context plumbing to a provider `before` hook once
71+ // @openfeature /web-sdk supports returned EvaluationContext values for web hooks.
72+ // Watch upstream packages/web/src/hooks/hook.ts for the before return changing from `void`,
73+ // and packages/web/src/client/internal/open-feature-client.ts for `beforeHooks` merging that
74+ // result before calling the resolver and subsequent hooks. Return this stored context, not a
75+ // fresh RUM lookup, so targeting, flag configuration, and telemetry stay on the same identity.
76+ /** Effective context associated with the active flags configuration. */
77+ private evaluationContext : EvaluationContext = { }
78+
6779 status : ProviderStatus
6880
6981 private flagsConfiguration : FlagsConfiguration = { }
@@ -98,15 +110,15 @@ export class DatadogProvider implements Provider {
98110 this . hooks = [ ]
99111 this . events = new OpenFeatureEventEmitter ( )
100112
101- const isRumFeatureFlagTrackingEnabled = options . enableRumFeatureFlagTracking ?? true
102- if ( isRumFeatureFlagTrackingEnabled ) {
113+ this . isRumIntegrationEnabled = options . enableRumFeatureFlagTracking ?? true
114+ if ( this . isRumIntegrationEnabled ) {
103115 this . hooks . push ( createRumTrackingHook ( ) )
104116 }
105117
106118 // Add EVP flag evaluation hook.
107119 const isEvaluationTrackingEnabled = options . enableFlagEvaluationTracking ?? true
108120 if ( isEvaluationTrackingEnabled && this . configuration ) {
109- this . hooks . push ( createFlagEvalEVPHook ( this . configuration ) )
121+ this . hooks . push ( createFlagEvalEVPHook ( this . configuration , ( ) => this . evaluationContext ) )
110122 }
111123
112124 // Add proper exposure logging hook (creates batch internally)
@@ -116,7 +128,7 @@ export class DatadogProvider implements Provider {
116128 chromeStorage : chromeStorageIfAvailable ( ) ,
117129 storageKeySuffix : 'dd-of-browser' ,
118130 } )
119- this . hooks . push ( createExposureLoggingHook ( this . configuration , this . exposureCache ) )
131+ this . hooks . push ( createExposureLoggingHook ( this . configuration , this . exposureCache , ( ) => this . evaluationContext ) )
120132 }
121133
122134 if ( hasIndexedDB ( ) ) {
@@ -137,6 +149,8 @@ export class DatadogProvider implements Provider {
137149 }
138150
139151 private setContext ( context : EvaluationContext ) : Promise < void > {
152+ const evaluationContext = this . isRumIntegrationEnabled ? enrichEvaluationContextWithRumUser ( context ) : context
153+
140154 if ( this . status === ProviderStatus . NOT_READY ) {
141155 // we're initializing, no status changes necessary
142156 } else {
@@ -155,7 +169,7 @@ export class DatadogProvider implements Provider {
155169 // Important: OF SDK awaits for all onContextChange calls to exit
156170 // before marking the provider as ready. Make sure to respect
157171 // `signal`, so we don't block OF SDK unnecessarily.
158- this . latestContextUpdate = this . retrieveFlagsConfiguration ( context , { signal } )
172+ this . latestContextUpdate = this . retrieveFlagsConfiguration ( evaluationContext , { signal } )
159173 . then ( ( result ) =>
160174 // New configuration might require clearing exposure
161175 // cache. One example of this is updating experiment
@@ -184,6 +198,7 @@ export class DatadogProvider implements Provider {
184198 // scheduling).
185199
186200 this . flagsConfiguration = config
201+ this . evaluationContext = evaluationContext
187202 this . status = fromCache ? ProviderStatus . STALE : ProviderStatus . READY
188203 this . events . emit ( ProviderEvents . ConfigurationChanged )
189204
@@ -268,34 +283,34 @@ export class DatadogProvider implements Provider {
268283 resolveBooleanEvaluation (
269284 flagKey : string ,
270285 defaultValue : boolean ,
271- context : EvaluationContext ,
286+ _context : EvaluationContext ,
272287 _logger : Logger
273288 ) : ResolutionDetails < boolean > {
274- return evaluate ( this . flagsConfiguration , 'boolean' , flagKey , defaultValue , context )
289+ return evaluate ( this . flagsConfiguration , 'boolean' , flagKey , defaultValue , this . evaluationContext )
275290 }
276291
277292 resolveStringEvaluation (
278293 flagKey : string ,
279294 defaultValue : string ,
280- context : EvaluationContext ,
295+ _context : EvaluationContext ,
281296 _logger : Logger
282297 ) : ResolutionDetails < string > {
283- return evaluate ( this . flagsConfiguration , 'string' , flagKey , defaultValue , context )
298+ return evaluate ( this . flagsConfiguration , 'string' , flagKey , defaultValue , this . evaluationContext )
284299 }
285300
286301 resolveNumberEvaluation (
287302 flagKey : string ,
288303 defaultValue : number ,
289- context : EvaluationContext ,
304+ _context : EvaluationContext ,
290305 _logger : Logger
291306 ) : ResolutionDetails < number > {
292- return evaluate ( this . flagsConfiguration , 'number' , flagKey , defaultValue , context )
307+ return evaluate ( this . flagsConfiguration , 'number' , flagKey , defaultValue , this . evaluationContext )
293308 }
294309
295310 resolveObjectEvaluation < T extends JsonValue > (
296311 flagKey : string ,
297312 defaultValue : T ,
298- context : EvaluationContext ,
313+ _context : EvaluationContext ,
299314 _logger : Logger
300315 ) : ResolutionDetails < T > {
301316 // type safety: OpenFeature interface requires us to return a
@@ -304,6 +319,12 @@ export class DatadogProvider implements Provider {
304319 // type-sound way because there's no runtime information passed to
305320 // learn what type the user expects. So it's up to the user to
306321 // make sure they pass the appropriate type.
307- return evaluate ( this . flagsConfiguration , 'object' , flagKey , defaultValue , context ) as ResolutionDetails < T >
322+ return evaluate (
323+ this . flagsConfiguration ,
324+ 'object' ,
325+ flagKey ,
326+ defaultValue ,
327+ this . evaluationContext
328+ ) as ResolutionDetails < T >
308329 }
309330}
0 commit comments