statsig 1.31.0 → 1.32.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ require 'constants'
2
2
  require 'statsig_event'
3
3
  require 'concurrent-ruby'
4
4
 
@@ -6,7 +6,7 @@ $gate_exposure_event = 'statsig::gate_exposure'
6
6
  $config_exposure_event = 'statsig::config_exposure'
7
7
  $layer_exposure_event = 'statsig::layer_exposure'
8
8
  $diagnostics_event = 'statsig::diagnostics'
9
- $ignored_metadata_keys = ['serverTime', 'configSyncTime', 'initTime', 'reason']
9
+ $ignored_metadata_keys = [:serverTime, :configSyncTime, :initTime, :reason]
10
10
  module Statsig
11
11
  class StatsigLogger
12
12
  def initialize(network, options, error_boundary)
@@ -41,9 +41,9 @@ module Statsig
41
41
  event = StatsigEvent.new($gate_exposure_event)
42
42
  event.user = user
43
43
  metadata = {
44
- 'gate' => gate_name,
45
- 'gateValue' => value.to_s,
46
- 'ruleID' => rule_id,
44
+ gate: gate_name,
45
+ gateValue: value.to_s,
46
+ ruleID: rule_id || Statsig::Const::EMPTY_STR,
47
47
  }
48
48
  return false if not is_unique_exposure(user, $gate_exposure_event, metadata)
49
49
  event.metadata = metadata
@@ -59,8 +59,8 @@ module Statsig
59
59
  event = StatsigEvent.new($config_exposure_event)
60
60
  event.user = user
61
61
  metadata = {
62
- 'config' => config_name,
63
- 'ruleID' => rule_id,
62
+ config: config_name,
63
+ ruleID: rule_id || Statsig::Const::EMPTY_STR,
64
64
  }
65
65
  return false if not is_unique_exposure(user, $config_exposure_event, metadata)
66
66
  event.metadata = metadata
@@ -72,8 +72,8 @@ module Statsig
72
72
  end
73
73
 
74
74
  def log_layer_exposure(user, layer, parameter_name, config_evaluation, context = nil)
75
- exposures = config_evaluation.undelegated_sec_exps
76
- allocated_experiment = ''
75
+ exposures = config_evaluation.undelegated_sec_exps || []
76
+ allocated_experiment = Statsig::Const::EMPTY_STR
77
77
  is_explicit = (config_evaluation.explicit_parameters&.include? parameter_name) || false
78
78
  if is_explicit
79
79
  allocated_experiment = config_evaluation.config_delegate
@@ -83,13 +83,13 @@ module Statsig
83
83
  event = StatsigEvent.new($layer_exposure_event)
84
84
  event.user = user
85
85
  metadata = {
86
- 'config' => layer.name,
87
- 'ruleID' => layer.rule_id,
88
- 'allocatedExperiment' => allocated_experiment,
89
- 'parameterName' => parameter_name,
90
- 'isExplicitParameter' => String(is_explicit),
86
+ config: layer.name,
87
+ ruleID: layer.rule_id || Statsig::Const::EMPTY_STR,
88
+ allocatedExperiment: allocated_experiment,
89
+ parameterName: parameter_name,
90
+ isExplicitParameter: String(is_explicit)
91
91
  }
92
- return false if not is_unique_exposure(user, $layer_exposure_event, metadata)
92
+ return false unless is_unique_exposure(user, $layer_exposure_event, metadata)
93
93
  event.metadata = metadata
94
94
  event.secondary_exposures = exposures.is_a?(Array) ? exposures : []
95
95
 
@@ -167,10 +167,10 @@ module Statsig
167
167
  return
168
168
  end
169
169
 
170
- event.metadata['reason'] = eval_details.reason
171
- event.metadata['configSyncTime'] = eval_details.config_sync_time
172
- event.metadata['initTime'] = eval_details.init_time
173
- event.metadata['serverTime'] = eval_details.server_time
170
+ event.metadata[:reason] = eval_details.reason
171
+ event.metadata[:configSyncTime] = eval_details.config_sync_time
172
+ event.metadata[:initTime] = eval_details.init_time
173
+ event.metadata[:serverTime] = eval_details.server_time
174
174
  end
175
175
 
176
176
  def safe_add_exposure_context(context, event)
@@ -178,8 +178,8 @@ module Statsig
178
178
  return
179
179
  end
180
180
 
181
- if context['is_manual_exposure']
182
- event.metadata['isManualExposure'] = 'true'
181
+ if context[:is_manual_exposure]
182
+ event.metadata[:isManualExposure] = 'true'
183
183
  end
184
184
  end
185
185
 
@@ -1,142 +1,92 @@
1
- # typed: true
2
-
3
- require 'sorbet-runtime'
4
1
  require_relative 'interfaces/data_store'
5
2
  require_relative 'interfaces/user_persistent_storage'
6
3
 
7
4
  ##
8
5
  # Configuration options for the Statsig SDK.
9
6
  class StatsigOptions
10
- extend T::Sig
11
7
 
12
- sig { returns(T.any(T::Hash[String, String], NilClass)) }
13
8
  # Hash you can use to set environment variables that apply to all of your users in
14
9
  # the same session and will be used for targeting purposes.
15
10
  # eg. { "tier" => "development" }
16
11
  attr_accessor :environment
17
12
 
18
- sig { returns(String) }
19
13
  # The base url used to make network calls to Statsig.
20
14
  # default: https://statsigapi.net/v1
21
15
  attr_accessor :api_url_base
22
16
 
23
17
  # The base url used specifically to call download_config_specs.
24
18
  # Takes precedence over api_url_base
25
- sig { returns(String) }
26
19
  attr_accessor :api_url_download_config_specs
27
20
 
28
- sig { returns(T.any(Float, Integer)) }
29
21
  # The interval (in seconds) to poll for changes to your Statsig configuration
30
22
  # default: 10s
31
23
  attr_accessor :rulesets_sync_interval
32
24
 
33
- sig { returns(T.any(Float, Integer)) }
34
25
  # The interval (in seconds) to poll for changes to your id lists
35
26
  # default: 60s
36
27
  attr_accessor :idlists_sync_interval
37
28
 
38
29
  # Disable background syncing for rulesets
39
- sig { returns(T::Boolean) }
40
30
  attr_accessor :disable_rulesets_sync
41
31
 
42
32
  # Disable background syncing for id lists
43
- sig { returns(T::Boolean) }
44
33
  attr_accessor :disable_idlists_sync
45
34
 
46
- sig { returns(T.any(Float, Integer)) }
47
35
  # How often to flush logs to Statsig
48
36
  # default: 60s
49
37
  attr_accessor :logging_interval_seconds
50
38
 
51
- sig { returns(Integer) }
52
39
  # The maximum number of events to batch before flushing logs to the server
53
40
  # default: 1000
54
41
  attr_accessor :logging_max_buffer_size
55
42
 
56
- sig { returns(T::Boolean) }
57
43
  # Restricts the SDK to not issue any network requests and only respond with default values (or local overrides)
58
44
  # default: false
59
45
  attr_accessor :local_mode
60
46
 
61
- sig { returns(T.any(String, NilClass)) }
62
47
  # A string that represents all rules for all feature gates, dynamic configs and experiments.
63
48
  # It can be provided to bootstrap the Statsig server SDK at initialization in case your server runs
64
49
  # into network issue or Statsig is down temporarily.
65
50
  attr_accessor :bootstrap_values
66
51
 
67
- sig { returns(T.any(Method, Proc, NilClass)) }
68
52
  # A callback function that will be called anytime the rulesets are updated.
69
53
  attr_accessor :rules_updated_callback
70
54
 
71
- sig { returns(T.any(Statsig::Interfaces::IDataStore, NilClass)) }
72
55
  # A class that extends IDataStore. Can be used to provide values from a
73
56
  # common data store (like Redis) to initialize the Statsig SDK.
74
57
  attr_accessor :data_store
75
58
 
76
- sig { returns(Integer) }
77
59
  # The number of threads allocated to syncing IDLists.
78
60
  # default: 3
79
61
  attr_accessor :idlist_threadpool_size
80
62
 
81
- sig { returns(Integer) }
82
63
  # The number of threads allocated to posting event logs.
83
64
  # default: 3
84
65
  attr_accessor :logger_threadpool_size
85
66
 
86
- sig { returns(T::Boolean) }
87
67
  # Should diagnostics be logged. These include performance metrics for initialize.
88
68
  # default: false
89
69
  attr_accessor :disable_diagnostics_logging
90
70
 
91
- sig { returns(T::Boolean) }
92
71
  # Statsig utilizes Sorbet (https://sorbet.org) to ensure type safety of the SDK. This includes logging
93
72
  # to console when errors are detected. You can disable this logging by setting this flag to true.
94
73
  # default: false
95
74
  attr_accessor :disable_sorbet_logging_handlers
96
75
 
97
- sig { returns(T.any(Integer, NilClass)) }
98
76
  # Number of seconds before a network call is timed out
99
77
  attr_accessor :network_timeout
100
78
 
101
- sig { returns(Integer) }
102
79
  # Number of times to retry sending a batch of failed log events
103
80
  attr_accessor :post_logs_retry_limit
104
81
 
105
- sig { returns(T.any(Method, Proc, Integer, NilClass)) }
106
82
  # The number of seconds, or a function that returns the number of seconds based on the number of retries remaining
107
83
  # which overrides the default backoff time between retries
108
84
  attr_accessor :post_logs_retry_backoff
109
85
 
110
- sig { returns(T.any(Statsig::Interfaces::IUserPersistentStorage, NilClass)) }
111
86
  # A storage adapter for persisted values. Can be used for sticky bucketing users in experiments.
112
87
  # Implements Statsig::Interfaces::IUserPersistentStorage.
113
88
  attr_accessor :user_persistent_storage
114
89
 
115
- sig do
116
- params(
117
- environment: T.any(T::Hash[String, String], NilClass),
118
- api_url_base: T.nilable(String),
119
- api_url_download_config_specs: T.any(String, NilClass),
120
- rulesets_sync_interval: T.any(Float, Integer),
121
- idlists_sync_interval: T.any(Float, Integer),
122
- disable_rulesets_sync: T::Boolean,
123
- disable_idlists_sync: T::Boolean,
124
- logging_interval_seconds: T.any(Float, Integer),
125
- logging_max_buffer_size: Integer,
126
- local_mode: T::Boolean,
127
- bootstrap_values: T.any(String, NilClass),
128
- rules_updated_callback: T.any(Method, Proc, NilClass),
129
- data_store: T.any(Statsig::Interfaces::IDataStore, NilClass),
130
- idlist_threadpool_size: Integer,
131
- logger_threadpool_size: Integer,
132
- disable_diagnostics_logging: T::Boolean,
133
- disable_sorbet_logging_handlers: T::Boolean,
134
- network_timeout: T.any(Integer, NilClass),
135
- post_logs_retry_limit: Integer,
136
- post_logs_retry_backoff: T.any(Method, Proc, Integer, NilClass),
137
- user_persistent_storage: T.any(Statsig::Interfaces::IUserPersistentStorage, NilClass)
138
- ).void
139
- end
140
90
  def initialize(
141
91
  environment = nil,
142
92
  api_url_base = nil,
data/lib/statsig_user.rb CHANGED
@@ -1,65 +1,49 @@
1
- # typed: true
2
-
3
- require 'sorbet-runtime'
4
1
  require 'json'
2
+ require 'constants'
5
3
 
6
4
  ##
7
5
  # The user object to be evaluated against your Statsig configurations (gates/experiments/dynamic configs).
8
6
  class StatsigUser
9
- extend T::Sig
10
7
 
11
- sig { returns(T.any(String, NilClass)) }
12
8
  # An identifier for this user. Evaluated against the User ID criteria. (https://docs.statsig.com/feature-gates/conditions#userid)
13
9
  attr_accessor :user_id
14
10
 
15
- sig { returns(T.any(String, NilClass)) }
16
11
  # An identifier for this user. Evaluated against the Email criteria. (https://docs.statsig.com/feature-gates/conditions#email)
17
12
  attr_accessor :email
18
13
 
19
- sig { returns(T.any(String, NilClass)) }
20
14
  # An IP address associated with this user. Evaluated against the IP Address criteria. (https://docs.statsig.com/feature-gates/conditions#ip)
21
15
  attr_accessor :ip
22
16
 
23
- sig { returns(T.any(String, NilClass)) }
24
17
  # A user agent string associated with this user. Evaluated against Browser Version and Name (https://docs.statsig.com/feature-gates/conditions#browser-version)
25
18
  attr_accessor :user_agent
26
19
 
27
- sig { returns(T.any(String, NilClass)) }
28
20
  # The country code associated with this user (e.g New Zealand => NZ). Evaluated against the Country criteria. (https://docs.statsig.com/feature-gates/conditions#country)
29
21
  attr_accessor :country
30
22
 
31
- sig { returns(T.any(String, NilClass)) }
32
23
  # An locale for this user.
33
24
  attr_accessor :locale
34
25
 
35
- sig { returns(T.any(String, NilClass)) }
36
26
  # The current app version the user is interacting with. Evaluated against the App Version criteria. (https://docs.statsig.com/feature-gates/conditions#app-version)
37
27
  attr_accessor :app_version
38
28
 
39
- sig { returns(T.any(T::Hash[String, String], NilClass)) }
40
29
  # A Hash you can use to set environment variables that apply to this user. e.g. { "tier" => "development" }
41
30
  attr_accessor :statsig_environment
42
31
 
43
- sig { returns(T.any(T::Hash[String, String], NilClass)) }
44
32
  # Any Custom IDs to associated with the user. (See https://docs.statsig.com/guides/experiment-on-custom-id-types)
45
33
  attr_accessor :custom_ids
46
34
 
47
- sig { returns(T.any(T::Hash[String, String], NilClass)) }
48
35
  # Any value you wish to use in evaluation, but do not want logged with events, can be stored in this field.
49
36
  attr_accessor :private_attributes
50
37
 
51
- sig { returns(T.any(T::Hash[String, T.untyped], NilClass)) }
52
38
  def custom
53
39
  @custom
54
40
  end
55
41
 
56
- sig { params(value: T.any(T::Hash[String, T.untyped], NilClass)).void }
57
42
  # Any custom fields for this user. Evaluated against the Custom criteria. (https://docs.statsig.com/feature-gates/conditions#custom)
58
43
  def custom=(value)
59
44
  @custom = value.is_a?(Hash) ? value : Hash.new
60
45
  end
61
46
 
62
- sig { params(user_hash: T.any(T::Hash[T.any(String, Symbol), T.untyped], NilClass)).void }
63
47
  def initialize(user_hash)
64
48
  the_hash = user_hash
65
49
  begin
@@ -83,55 +67,56 @@ class StatsigUser
83
67
 
84
68
  def serialize(for_logging)
85
69
  hash = {
86
- 'userID' => @user_id,
87
- 'email' => @email,
88
- 'ip' => @ip,
89
- 'userAgent' => @user_agent,
90
- 'country' => @country,
91
- 'locale' => @locale,
92
- 'appVersion' => @app_version,
93
- 'custom' => @custom,
94
- 'statsigEnvironment' => @statsig_environment,
95
- 'privateAttributes' => @private_attributes,
96
- 'customIDs' => @custom_ids,
70
+ :userID => @user_id,
71
+ :email => @email,
72
+ :ip => @ip,
73
+ :userAgent => @user_agent,
74
+ :country => @country,
75
+ :locale => @locale,
76
+ :appVersion => @app_version,
77
+ :custom => @custom,
78
+ :statsigEnvironment => @statsig_environment,
79
+ :privateAttributes => @private_attributes,
80
+ :customIDs => @custom_ids,
97
81
  }
98
82
  if for_logging
99
- hash.delete('privateAttributes')
83
+ hash.delete(:privateAttributes)
100
84
  end
101
85
  hash.compact
102
86
  end
103
87
 
104
- def to_hash_without_stable_id()
88
+ def to_hash_without_stable_id
105
89
  hash = {}
90
+
106
91
  if @user_id != nil
107
- hash['userID'] = @user_id
92
+ hash[:userID] = @user_id
108
93
  end
109
94
  if @email != nil
110
- hash['email'] = @email
95
+ hash[:email] = @email
111
96
  end
112
97
  if @ip != nil
113
- hash['ip'] = @ip
98
+ hash[:ip] = @ip
114
99
  end
115
100
  if @user_agent != nil
116
- hash['userAgent'] = @user_agent
101
+ hash[:userAgent] = @user_agent
117
102
  end
118
103
  if @country != nil
119
- hash['country'] = @country
104
+ hash[:country] = @country
120
105
  end
121
106
  if @locale != nil
122
- hash['locale'] = @locale
107
+ hash[:locale] = @locale
123
108
  end
124
109
  if @app_version != nil
125
- hash['appVersion'] = @app_version
110
+ hash[:appVersion] = @app_version
126
111
  end
127
112
  if @custom != nil
128
- hash['custom'] = Statsig::HashUtils.sortHash(@custom)
113
+ hash[:custom] = Statsig::HashUtils.sortHash(@custom)
129
114
  end
130
115
  if @statsig_environment != nil
131
- hash['statsigEnvironment'] = @statsig_environment.clone.sort_by { |key| key }.to_h
116
+ hash[:statsigEnvironment] = @statsig_environment.clone.sort_by { |key| key }.to_h
132
117
  end
133
118
  if @private_attributes != nil
134
- hash['privateAttributes'] = Statsig::HashUtils.sortHash(@private_attributes)
119
+ hash[:privateAttributes] = Statsig::HashUtils.sortHash(@private_attributes)
135
120
  end
136
121
  custom_ids = {}
137
122
  if @custom_ids != nil
@@ -140,32 +125,12 @@ class StatsigUser
140
125
  custom_ids.delete("stableID")
141
126
  end
142
127
  end
143
- hash['customIDs'] = custom_ids.sort_by { |key| key }.to_h
128
+ hash[:customIDs] = custom_ids.sort_by { |key| key }.to_h
144
129
  return Statsig::HashUtils.djb2ForHash(hash.sort_by { |key| key }.to_h)
145
130
  end
146
131
 
147
- def value_lookup
148
- {
149
- 'userID' => @user_id,
150
- 'userid' => @user_id,
151
- 'user_id' => @user_id,
152
- 'email' => @email,
153
- 'ip' => @ip,
154
- 'userAgent' => @user_agent,
155
- 'useragent' => @user_agent,
156
- 'user_agent' => @user_agent,
157
- 'country' => @country,
158
- 'locale' => @locale,
159
- 'appVersion' => @app_version,
160
- 'appversion' => @app_version,
161
- 'app_version' => @app_version,
162
- 'custom' => @custom,
163
- 'privateAttributes' => @private_attributes,
164
- }
165
- end
166
-
167
132
  def get_unit_id(id_type)
168
- if id_type.is_a?(String) && id_type.downcase != 'userid'
133
+ if id_type.is_a?(String) && id_type != Statsig::Const::CML_USER_ID
169
134
  return nil unless @custom_ids.is_a? Hash
170
135
 
171
136
  return @custom_ids[id_type] || @custom_ids[id_type.downcase]
@@ -175,12 +140,6 @@ class StatsigUser
175
140
 
176
141
  private
177
142
 
178
- sig {
179
- params(user_hash: T.any(T::Hash[T.any(String, Symbol), T.untyped], NilClass),
180
- keys: T::Array[Symbol],
181
- type: T.untyped)
182
- .returns(T.untyped)
183
- }
184
143
  # Pulls fields from the user hash via Symbols and Strings
185
144
  def from_hash(user_hash, keys, type)
186
145
  if user_hash.nil?
data/lib/ua_parser.rb CHANGED
@@ -1,4 +1,4 @@
1
- # typed: true
1
+
2
2
  require 'user_agent_parser'
3
3
 
4
4
  module UAParser
data/lib/uri_helper.rb CHANGED
@@ -1,24 +1,16 @@
1
- # typed: true
2
-
3
- require 'sorbet-runtime'
4
-
5
1
  class URIHelper
6
2
  class URIBuilder
7
- extend T::Sig
8
3
 
9
- sig { returns(StatsigOptions) }
10
4
  attr_accessor :options
11
5
 
12
- sig { params(options: StatsigOptions).void }
13
6
  def initialize(options)
14
7
  @options = options
15
8
  end
16
9
 
17
- sig { params(endpoint: String).returns(String) }
18
10
  def build_url(endpoint)
19
11
  api = @options.api_url_base
20
12
  if endpoint.include?('download_config_specs')
21
- api = T.must(@options.api_url_download_config_specs)
13
+ api = @options.api_url_download_config_specs
22
14
  end
23
15
  unless api.end_with?('/')
24
16
  api += '/'
@@ -1,27 +1,17 @@
1
- # typed: false
2
-
3
- require 'sorbet-runtime'
4
1
  require 'statsig_options'
5
2
 
6
3
  module Statsig
7
- UserPersistedValues = T.type_alias { T::Hash[String, Hash] }
8
-
9
4
  class UserPersistentStorageUtils
10
- extend T::Sig
11
5
 
12
- sig { returns(T::Hash[String, UserPersistedValues]) }
13
6
  attr_accessor :cache
14
7
 
15
- sig { returns(T.nilable(Interfaces::IUserPersistentStorage)) }
16
8
  attr_accessor :storage
17
9
 
18
- sig { params(options: StatsigOptions).void }
19
10
  def initialize(options)
20
11
  @storage = options.user_persistent_storage
21
12
  @cache = {}
22
13
  end
23
14
 
24
- sig { params(user: StatsigUser, id_type: String).returns(T.nilable(UserPersistedValues)) }
25
15
  def get_user_persisted_values(user, id_type)
26
16
  key = self.class.get_storage_key(user, id_type)
27
17
  return @cache[key] unless @cache[key].nil?
@@ -29,7 +19,6 @@ module Statsig
29
19
  return load_from_storage(key)
30
20
  end
31
21
 
32
- sig { params(key: String).returns(T.nilable(UserPersistedValues)) }
33
22
  def load_from_storage(key)
34
23
  return if @storage.nil?
35
24
 
@@ -50,7 +39,6 @@ module Statsig
50
39
  return nil
51
40
  end
52
41
 
53
- sig { params(user: StatsigUser, id_type: String, user_persisted_values: UserPersistedValues).void }
54
42
  def save_to_storage(user, id_type, user_persisted_values)
55
43
  return if @storage.nil?
56
44
 
@@ -65,7 +53,6 @@ module Statsig
65
53
  end
66
54
  end
67
55
 
68
- sig { params(user: StatsigUser, id_type: String, config_name: String).void }
69
56
  def remove_experiment_from_storage(user, id_type, config_name)
70
57
  persisted_values = get_user_persisted_values(user, id_type)
71
58
  unless persisted_values.nil?
@@ -74,7 +61,6 @@ module Statsig
74
61
  end
75
62
  end
76
63
 
77
- sig { params(user_persisted_values: T.nilable(UserPersistedValues), config_name: String, evaluation: ConfigResult).void }
78
64
  def add_evaluation_to_user_persisted_values(user_persisted_values, config_name, evaluation)
79
65
  if user_persisted_values.nil?
80
66
  user_persisted_values = {}
@@ -84,21 +70,18 @@ module Statsig
84
70
 
85
71
  private
86
72
 
87
- sig { params(values_string: String).returns(T.nilable(UserPersistedValues)) }
88
73
  def self.parse(values_string)
89
74
  return JSON.parse(values_string)
90
75
  rescue JSON::ParserError
91
76
  return nil
92
77
  end
93
78
 
94
- sig { params(values_object: UserPersistedValues).returns(T.nilable(String)) }
95
79
  def self.stringify(values_object)
96
80
  return JSON.generate(values_object)
97
81
  rescue StandardError
98
82
  return nil
99
83
  end
100
84
 
101
- sig { params(user: StatsigUser, id_type: String).returns(String) }
102
85
  def self.get_storage_key(user, id_type)
103
86
  "#{user.get_unit_id(id_type)}:#{id_type}"
104
87
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: statsig
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.31.0
4
+ version: 1.32.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Statsig, Inc
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-24 00:00:00.000000000 Z
11
+ date: 2024-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -322,8 +322,10 @@ executables: []
322
322
  extensions: []
323
323
  extra_rdoc_files: []
324
324
  files:
325
+ - lib/api_config.rb
325
326
  - lib/client_initialize_helpers.rb
326
327
  - lib/config_result.rb
328
+ - lib/constants.rb
327
329
  - lib/diagnostics.rb
328
330
  - lib/dynamic_config.rb
329
331
  - lib/error_boundary.rb