statsig 1.31.1 → 1.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1afc6737d00e614429706bdcac895ecd61ef3f858fe152bc21c407470ec8168f
4
- data.tar.gz: cbdb4311dd2505d47ada5f78105ec0203e24edd6274161d16b67b196aa68596b
3
+ metadata.gz: 56f4bfc568fa70750a5dc1376ffffacd1163344c63750492e0e0ff841fd73d18
4
+ data.tar.gz: 6e41d012096437a58a9ceea49c0aa5d71532d06d273b37593afcd7cb9bc07297
5
5
  SHA512:
6
- metadata.gz: 113b3cbc430583fd2144ab7f6dc9188e3e2c87079fb188bc931c954ffe51c18c849373ed53fee2b71c87f6abb76a54f66519475eb5bfd95bf00c29cc21f2e4c0
7
- data.tar.gz: a4f7632a2af82ea4052ed1c94b9b651e7fd7b6ac88010d4d18b77038d374d2833e25443768152f54ab68f6710f48a6c5ada634199d6b4d55f7501074674d3a82
6
+ metadata.gz: 7060859db57bed3e98e372c1b3808f53802bb1c7e4e76f70b366e138c022d1aef522605457d8e69f8eb029394c8bb8c32e1aa1eb0933d4fcd8746f60452afac3
7
+ data.tar.gz: a0857b56731a9fab6d53748700a932fc3d6a3c7b065dd8ce54d03bf89274002f215e6ae39fa0b72d49c60cb4c7cc11307f7e4d3b1f965f7f4f5a721545712978
data/lib/api_config.rb ADDED
@@ -0,0 +1,128 @@
1
+ require 'constants'
2
+
3
+ class UnsupportedConfigException < StandardError
4
+ end
5
+
6
+ module Statsig
7
+ class APIConfig
8
+ attr_accessor :name, :type, :is_active, :salt, :default_value, :enabled,
9
+ :rules, :id_type, :entity, :explicit_parameters, :has_shared_params, :target_app_ids
10
+
11
+ def initialize(name:, type:, is_active:, salt:, default_value:, enabled:, rules:, id_type:, entity:,
12
+ explicit_parameters: nil, has_shared_params: nil, target_app_ids: nil)
13
+ @name = name
14
+ @type = type.to_sym unless entity.nil?
15
+ @is_active = is_active
16
+ @salt = salt
17
+ @default_value = JSON.parse(JSON.generate(default_value))
18
+ @enabled = enabled
19
+ @rules = rules
20
+ @id_type = id_type
21
+ @entity = entity.to_sym unless entity.nil?
22
+ @explicit_parameters = explicit_parameters
23
+ @has_shared_params = has_shared_params
24
+ @target_app_ids = target_app_ids
25
+ end
26
+
27
+ def self.from_json(json)
28
+ new(
29
+ name: json[:name],
30
+ type: json[:type],
31
+ is_active: json[:isActive],
32
+ salt: json[:salt],
33
+ default_value: json[:defaultValue] || {},
34
+ enabled: json[:enabled],
35
+ rules: json[:rules]&.map do |rule|
36
+ APIRule.from_json(rule)
37
+ end,
38
+ id_type: json[:idType],
39
+ entity: json[:entity],
40
+ explicit_parameters: json[:explicitParameters],
41
+ has_shared_params: json[:hasSharedParams],
42
+ target_app_ids: json[:targetAppIDs]
43
+ )
44
+ end
45
+ end
46
+ end
47
+
48
+ module Statsig
49
+ class APIRule
50
+
51
+ attr_accessor :name, :pass_percentage, :return_value, :id, :salt,
52
+ :conditions, :id_type, :group_name, :config_delegate, :is_experiment_group
53
+
54
+ def initialize(name:, pass_percentage:, return_value:, id:, salt:, conditions:, id_type:,
55
+ group_name: nil, config_delegate: nil, is_experiment_group: nil)
56
+ @name = name
57
+ @pass_percentage = pass_percentage.to_f
58
+ @return_value = JSON.parse(JSON.generate(return_value))
59
+ @id = id
60
+ @salt = salt
61
+ @conditions = conditions
62
+ @id_type = id_type
63
+ @group_name = group_name
64
+ @config_delegate = config_delegate
65
+ @is_experiment_group = is_experiment_group
66
+ end
67
+
68
+ def self.from_json(json)
69
+ new(
70
+ name: json[:name],
71
+ pass_percentage: json[:passPercentage],
72
+ return_value: json[:returnValue] || {},
73
+ id: json[:id],
74
+ salt: json[:salt],
75
+ conditions: json[:conditions]&.map do |condition|
76
+ APICondition.from_json(condition)
77
+ end,
78
+ id_type: json[:idType],
79
+ group_name: json[:groupName],
80
+ config_delegate: json[:configDelegate],
81
+ is_experiment_group: json[:isExperimentGroup]
82
+ )
83
+ end
84
+ end
85
+ end
86
+
87
+ module Statsig
88
+ class APICondition
89
+
90
+ attr_accessor :type, :target_value, :operator, :field, :additional_values, :id_type
91
+
92
+ def initialize(type:, target_value:, operator:, field:, additional_values:, id_type:)
93
+ @type = type.to_sym unless type.nil?
94
+ @target_value = target_value
95
+ @operator = operator.to_sym unless operator.nil?
96
+ @field = field
97
+ @additional_values = additional_values || {}
98
+ @id_type = id_type
99
+ end
100
+
101
+ def self.from_json(json)
102
+ operator = json[:operator]
103
+ unless operator.nil?
104
+ operator = operator&.downcase&.to_sym
105
+ unless Const::SUPPORTED_OPERATORS.include?(operator)
106
+ raise UnsupportedConfigException
107
+ end
108
+ end
109
+
110
+ type = json[:type]
111
+ unless type.nil?
112
+ type = type&.downcase&.to_sym
113
+ unless Const::SUPPORTED_CONDITION_TYPES.include?(type)
114
+ raise UnsupportedConfigException
115
+ end
116
+ end
117
+
118
+ new(
119
+ type: json[:type],
120
+ target_value: json[:targetValue],
121
+ operator: json[:operator],
122
+ field: json[:field],
123
+ additional_values: json[:additionalValues],
124
+ id_type: json[:idType]
125
+ )
126
+ end
127
+ end
128
+ end
@@ -1,148 +1,159 @@
1
- # typed: true
2
-
3
1
  require_relative 'hash_utils'
4
- require 'sorbet-runtime'
5
2
 
3
+ require 'constants'
6
4
 
7
- module ClientInitializeHelpers
5
+ module Statsig
8
6
  class ResponseFormatter
9
- extend T::Sig
10
-
11
- def initialize(evaluator, user, hash, client_sdk_key)
12
- @evaluator = evaluator
13
- @user = user
14
- @specs = evaluator.spec_store.get_raw_specs
15
- @hash = hash
16
- @client_sdk_key = client_sdk_key
17
- end
18
-
19
- def get_responses(key)
20
- @specs[key]
21
- .map { |name, spec| to_response(name, spec) }
22
- .delete_if { |v| v.nil? }.to_h
23
- end
24
-
25
- private
26
-
27
- sig { params(secondary_exposures: T::Array[T::Hash[String, String]]).returns(T::Array[T::Hash[String, String]]) }
28
- def filter_segments_from_secondary_exposures(secondary_exposures)
29
- secondary_exposures.reject do |exposure|
30
- exposure['gate'].to_s.start_with?('segment:')
7
+ def self.get_responses(
8
+ entities,
9
+ evaluator,
10
+ user,
11
+ client_sdk_key,
12
+ hash_algo,
13
+ include_exposures: true,
14
+ include_local_overrides: false
15
+ )
16
+ result = {}
17
+ entities.each do |name, spec|
18
+ hashed_name, value = to_response(name, spec, evaluator, user, client_sdk_key, hash_algo, include_exposures, include_local_overrides)
19
+ if !hashed_name.nil? && !value.nil?
20
+ result[hashed_name] = value
21
+ end
31
22
  end
23
+
24
+ result
32
25
  end
33
26
 
34
- def to_response(config_name, config_spec)
35
- target_app_id = @evaluator.spec_store.get_app_id_for_sdk_key(@client_sdk_key)
36
- config_target_apps = config_spec['targetAppIDs']
27
+ def self.to_response(config_name, config_spec, evaluator, user, client_sdk_key, hash_algo, include_exposures, include_local_overrides)
28
+ target_app_id = evaluator.spec_store.get_app_id_for_sdk_key(client_sdk_key)
29
+ config_target_apps = config_spec.target_app_ids
37
30
 
38
31
  unless target_app_id.nil? || (!config_target_apps.nil? && config_target_apps.include?(target_app_id))
39
32
  return nil
40
33
  end
41
34
 
42
- eval_result = @evaluator.eval_spec(@user, config_spec)
43
- if eval_result.nil?
35
+ category = config_spec.type
36
+ entity_type = config_spec.entity
37
+ if entity_type == :segment || entity_type == :holdout
44
38
  return nil
45
39
  end
46
40
 
47
- category = config_spec['type']
48
- entity_type = config_spec['entity']
41
+ if include_local_overrides
42
+ case category
43
+ when :feature_gate
44
+ local_override = evaluator.lookup_gate_override(config_name)
45
+ when :dynamic_config
46
+ local_override = evaluator.lookup_config_override(config_name)
47
+ end
48
+ end
49
49
 
50
- result = {}
50
+ if local_override.nil?
51
+ eval_result = ConfigResult.new(
52
+ name: config_name,
53
+ disable_evaluation_details: true,
54
+ disable_exposures: !include_exposures
55
+ )
56
+ evaluator.eval_spec(user, config_spec, eval_result)
57
+ else
58
+ eval_result = local_override
59
+ end
51
60
 
52
- case category
61
+ result = {}
53
62
 
54
- when 'feature_gate'
55
- if entity_type == 'segment' || entity_type == 'holdout'
56
- return nil
57
- end
63
+ result[:id_type] = eval_result.id_type
64
+ unless eval_result.group_name.nil?
65
+ result[:group_name] = eval_result.group_name
66
+ end
58
67
 
59
- result['value'] = eval_result.gate_value
60
- result["group_name"] = eval_result.group_name
61
- result["id_type"] = eval_result.id_type
62
- when 'dynamic_config'
63
- id_type = config_spec['idType']
64
- result['value'] = eval_result.json_value
65
- result["group"] = eval_result.rule_id
66
- result["group_name"] = eval_result.group_name
67
- result["id_type"] = eval_result.id_type
68
- result["is_device_based"] = id_type.is_a?(String) && id_type.downcase == 'stableid'
68
+ case category
69
+ when :feature_gate
70
+ result[:value] = eval_result.gate_value
71
+ when :dynamic_config
72
+ id_type = config_spec.id_type
73
+ result[:value] = eval_result.json_value
74
+ result[:group] = eval_result.rule_id
75
+ result[:is_device_based] = id_type.is_a?(String) && id_type.downcase == Statsig::Const::STABLEID
69
76
  else
70
77
  return nil
71
78
  end
72
79
 
73
- if entity_type == 'experiment'
74
- populate_experiment_fields(config_name, config_spec, eval_result, result)
80
+ if entity_type == :experiment
81
+ populate_experiment_fields(name, config_spec, eval_result, result, evaluator)
75
82
  end
76
83
 
77
- if entity_type == 'layer'
78
- populate_layer_fields(config_spec, eval_result, result)
79
- result.delete('id_type') # not exposed for layer configs in /initialize
84
+ if entity_type == :layer
85
+ populate_layer_fields(config_spec, eval_result, result, evaluator, hash_algo, include_exposures)
86
+ result.delete(:id_type) # not exposed for layer configs in /initialize
80
87
  end
81
88
 
82
- hashed_name = hash_name(config_name)
83
- [hashed_name, result.merge(
84
- {
85
- "name" => hashed_name,
86
- "rule_id" => eval_result.rule_id,
87
- "secondary_exposures" => clean_exposures(eval_result.secondary_exposures)
88
- }).compact]
89
+ hashed_name = hash_name(config_name, hash_algo)
90
+
91
+ result[:name] = hashed_name
92
+ result[:rule_id] = eval_result.rule_id
93
+
94
+ if include_exposures
95
+ result[:secondary_exposures] = clean_exposures(eval_result.secondary_exposures)
96
+ end
97
+
98
+ [hashed_name, result]
89
99
  end
90
100
 
91
- def clean_exposures(exposures)
101
+ def self.clean_exposures(exposures)
92
102
  seen = {}
93
103
  exposures.reject do |exposure|
94
- key = "#{exposure["gate"]}|#{exposure["gateValue"]}|#{exposure["ruleID"]}}"
104
+ key = "#{exposure[:gate]}|#{exposure[:gateValue]}|#{exposure[:ruleID]}}"
95
105
  should_reject = seen[key]
96
106
  seen[key] = true
97
107
  should_reject == true
98
108
  end
99
109
  end
100
110
 
101
- def populate_experiment_fields(config_name, config_spec, eval_result, result)
102
- result["is_user_in_experiment"] = eval_result.is_experiment_group
103
- result["is_experiment_active"] = config_spec['isActive'] == true
111
+ def self.populate_experiment_fields(config_name, config_spec, eval_result, result, evaluator)
112
+ result[:is_user_in_experiment] = eval_result.is_experiment_group
113
+ result[:is_experiment_active] = config_spec.is_active == true
104
114
 
105
- if config_spec['hasSharedParams'] != true
115
+ if config_spec.has_shared_params != true
106
116
  return
107
117
  end
108
118
 
109
- result["is_in_layer"] = true
110
- result["explicit_parameters"] = config_spec["explicitParameters"] || []
119
+ result[:is_in_layer] = true
120
+ result[:explicit_parameters] = config_spec.explicit_parameters || []
111
121
 
112
- layer_name = @specs[:experiment_to_layer][config_name]
113
- if layer_name.nil? || @specs[:layers][layer_name].nil?
122
+ layer_name = evaluator.spec_store.experiment_to_layer[config_name]
123
+ if layer_name.nil? || evaluator.spec_store.layers[layer_name].nil?
114
124
  return
115
125
  end
116
126
 
117
- layer = @specs[:layers][layer_name]
118
- result["value"] = layer["defaultValue"].merge(result["value"])
127
+ layer = evaluator.spec_store.layers[layer_name]
128
+ result[:value] = layer[:defaultValue].merge(result[:value])
119
129
  end
120
130
 
121
- def populate_layer_fields(config_spec, eval_result, result)
131
+ def self.populate_layer_fields(config_spec, eval_result, result, evaluator, hash_algo, include_exposures)
122
132
  delegate = eval_result.config_delegate
123
- result["explicit_parameters"] = config_spec["explicitParameters"] || []
133
+ result[:explicit_parameters] = config_spec.explicit_parameters || []
124
134
 
125
135
  if delegate.nil? == false && delegate.empty? == false
126
- delegate_spec = @specs[:configs][delegate]
127
- delegate_result = @evaluator.eval_spec(@user, delegate_spec)
136
+ delegate_spec = evaluator.spec_store.configs[delegate]
128
137
 
129
- result["allocated_experiment_name"] = hash_name(delegate)
130
- result["is_user_in_experiment"] = delegate_result.is_experiment_group
131
- result["is_experiment_active"] = delegate_spec['isActive'] == true
132
- result["explicit_parameters"] = delegate_spec["explicitParameters"] || []
138
+ result[:allocated_experiment_name] = hash_name(delegate, hash_algo)
139
+ result[:is_user_in_experiment] = eval_result.is_experiment_group
140
+ result[:is_experiment_active] = delegate_spec.is_active == true
141
+ result[:explicit_parameters] = delegate_spec.explicit_parameters || []
133
142
  end
134
143
 
135
- result["undelegated_secondary_exposures"] = clean_exposures(eval_result.undelegated_sec_exps || [])
144
+ if include_exposures
145
+ result[:undelegated_secondary_exposures] = clean_exposures(eval_result.undelegated_sec_exps || [])
146
+ end
136
147
  end
137
148
 
138
- def hash_name(name)
139
- case @hash
140
- when 'none'
149
+ def self.hash_name(name, hash_algo)
150
+ case hash_algo
151
+ when Statsig::Const::NONE
141
152
  return name
142
- when 'sha256'
143
- return Statsig::HashUtils.sha256(name)
144
- when 'djb2'
153
+ when Statsig::Const::DJB2
145
154
  return Statsig::HashUtils.djb2(name)
155
+ else
156
+ return Statsig::HashUtils.sha256(name)
146
157
  end
147
158
  end
148
159
  end
data/lib/config_result.rb CHANGED
@@ -1,10 +1,5 @@
1
- # typed: true
2
-
3
- require 'sorbet-runtime'
4
-
5
1
  module Statsig
6
2
  class ConfigResult
7
- extend T::Sig
8
3
 
9
4
  attr_accessor :name
10
5
  attr_accessor :gate_value
@@ -19,25 +14,30 @@ module Statsig
19
14
  attr_accessor :group_name
20
15
  attr_accessor :id_type
21
16
  attr_accessor :target_app_ids
17
+ attr_accessor :disable_evaluation_details
18
+ attr_accessor :disable_exposures
22
19
 
23
20
  def initialize(
24
- name,
25
- gate_value = false,
26
- json_value = {},
27
- rule_id = '',
28
- secondary_exposures = [],
29
- config_delegate = nil,
30
- explicit_parameters = [],
21
+ name:,
22
+ gate_value: false,
23
+ json_value: nil,
24
+ rule_id: nil,
25
+ secondary_exposures: [],
26
+ config_delegate: nil,
27
+ explicit_parameters: nil,
31
28
  is_experiment_group: false,
32
29
  evaluation_details: nil,
33
30
  group_name: nil,
34
- id_type: '',
35
- target_app_ids: nil)
31
+ id_type: nil,
32
+ target_app_ids: nil,
33
+ disable_evaluation_details: false,
34
+ disable_exposures: false
35
+ )
36
36
  @name = name
37
37
  @gate_value = gate_value
38
38
  @json_value = json_value
39
39
  @rule_id = rule_id
40
- @secondary_exposures = secondary_exposures.is_a?(Array) ? secondary_exposures : []
40
+ @secondary_exposures = secondary_exposures
41
41
  @undelegated_sec_exps = @secondary_exposures
42
42
  @config_delegate = config_delegate
43
43
  @explicit_parameters = explicit_parameters
@@ -46,9 +46,10 @@ module Statsig
46
46
  @group_name = group_name
47
47
  @id_type = id_type
48
48
  @target_app_ids = target_app_ids
49
+ @disable_evaluation_details = disable_evaluation_details
50
+ @disable_exposures = disable_exposures
49
51
  end
50
52
 
51
- sig { params(config_name: String, user_persisted_values: UserPersistedValues).returns(T.nilable(ConfigResult)) }
52
53
  def self.from_user_persisted_values(config_name, user_persisted_values)
53
54
  sticky_values = user_persisted_values[config_name]
54
55
  return nil if sticky_values.nil?
@@ -56,22 +57,6 @@ module Statsig
56
57
  from_hash(config_name, sticky_values)
57
58
  end
58
59
 
59
- sig { params(config_name: String, hash: Hash).returns(ConfigResult) }
60
- def self.from_hash(config_name, hash)
61
- new(
62
- config_name,
63
- hash['gate_value'],
64
- hash['json_value'],
65
- hash['rule_id'],
66
- hash['secondary_exposures'],
67
- evaluation_details: EvaluationDetails.persisted(hash['config_sync_time'], hash['init_time']),
68
- group_name: hash['group_name'],
69
- id_type: hash['id_type'],
70
- target_app_ids: hash['target_app_ids']
71
- )
72
- end
73
-
74
- sig { returns(Hash) }
75
60
  def to_hash
76
61
  {
77
62
  json_value: @json_value,
data/lib/constants.rb ADDED
@@ -0,0 +1,60 @@
1
+ module Statsig
2
+ module Const
3
+ EMPTY_STR = ''.freeze
4
+
5
+ SUPPORTED_CONDITION_TYPES = Set.new(%i[
6
+ public fail_gate pass_gate ip_based ua_based user_field
7
+ environment_field current_time user_bucket unit_id
8
+ ]).freeze
9
+
10
+ SUPPORTED_OPERATORS = Set.new(%i[
11
+ gt gte lt lte version_gt version_gte version_lt version_lte
12
+ version_eq version_neq any none any_case_sensitive none_case_sensitive
13
+ str_starts_with_any str_ends_with_any str_contains_any str_contains_none
14
+ str_matches eq neq before after on in_segment_list not_in_segment_list
15
+ ]).freeze
16
+
17
+ APP_VERSION = 'app_version'.freeze
18
+ APPVERSION = 'appversion'.freeze
19
+ BROWSER_NAME = 'browser_name'.freeze
20
+ BROWSER_VERSION = 'browser_version'.freeze
21
+ BROWSERNAME = 'browsername'.freeze
22
+ BROWSERVERSION = 'browserversion'.freeze
23
+ CML_SHA_256 = 'sha256'.freeze
24
+ CML_USER_ID = 'userID'.freeze
25
+ COUNTRY = 'country'.freeze
26
+ DEFAULT = 'default'.freeze
27
+ DISABLED = 'disabled'.freeze
28
+ DJB2 = 'djb2'.freeze
29
+ EMAIL = 'email'.freeze
30
+ FALSE = 'false'.freeze
31
+ IP = 'ip'.freeze
32
+ LAYER = :layer
33
+ LOCALE = 'locale'.freeze
34
+ NONE = 'none'.freeze
35
+ OS_NAME = 'os_name'.freeze
36
+ OS_VERSION = 'os_version'.freeze
37
+ OSNAME = 'osname'.freeze
38
+ OSVERSION = 'osversion'.freeze
39
+ OVERRIDE = 'override'.freeze
40
+ Q_RIGHT_CHEVRON = 'Q>'.freeze
41
+ STABLEID = 'stableid'.freeze
42
+ STATSIG_RUBY_SDK = 'statsig-ruby-sdk'.freeze
43
+ TRUE = 'true'.freeze
44
+ USER_AGENT = 'user_agent'.freeze
45
+ USER_ID = 'user_id'.freeze
46
+ USERAGENT = 'useragent'.freeze
47
+ USERID = 'userid'.freeze
48
+
49
+ # Persisted Evaluations
50
+ GATE_VALUE = 'gate_value'.freeze
51
+ JSON_VALUE = 'json_value'.freeze
52
+ RULE_ID = 'rule_id'.freeze
53
+ SECONDARY_EXPOSURES = 'secondary_exposures'.freeze
54
+ GROUP_NAME = 'group_name'.freeze
55
+ ID_TYPE = 'id_type'.freeze
56
+ TARGET_APP_IDS = 'target_app_ids'.freeze
57
+ CONFIG_SYNC_TIME = 'config_sync_time'.freeze
58
+ INIT_TIME = 'init_time'.freeze
59
+ end
60
+ end
data/lib/diagnostics.rb CHANGED
@@ -1,15 +1,7 @@
1
- # typed: true
2
-
3
- require 'sorbet-runtime'
4
-
5
1
  module Statsig
6
2
  class Diagnostics
7
- extend T::Sig
8
-
9
- sig { returns(T::Hash[String, T::Array[T::Hash[Symbol, T.untyped]]]) }
10
3
  attr_reader :markers
11
4
 
12
- sig { returns(T::Hash[String, Numeric]) }
13
5
  attr_accessor :sample_rates
14
6
 
15
7
  def initialize()
@@ -17,16 +9,6 @@ module Statsig
17
9
  @sample_rates = {}
18
10
  end
19
11
 
20
- sig do
21
- params(
22
- key: String,
23
- action: String,
24
- step: T.any(String, NilClass),
25
- tags: T::Hash[Symbol, T.untyped],
26
- context: String
27
- ).void
28
- end
29
-
30
12
  def mark(key, action, step, tags, context)
31
13
  marker = {
32
14
  key: key,
@@ -47,14 +29,6 @@ module Statsig
47
29
  @markers[context].push(marker)
48
30
  end
49
31
 
50
- sig do
51
- params(
52
- context: String,
53
- key: String,
54
- step: T.any(String, NilClass),
55
- tags: T::Hash[Symbol, T.untyped]
56
- ).returns(Tracker)
57
- end
58
32
  def track(context, key, step = nil, tags = {})
59
33
  tracker = Tracker.new(self, context, key, step, tags)
60
34
  tracker.start(**tags)
@@ -87,17 +61,6 @@ module Statsig
87
61
  API_CALL_KEYS = %w[check_gate get_config get_experiment get_layer].freeze
88
62
 
89
63
  class Tracker
90
- extend T::Sig
91
-
92
- sig do
93
- params(
94
- diagnostics: Diagnostics,
95
- context: String,
96
- key: String,
97
- step: T.any(String, NilClass),
98
- tags: T::Hash[Symbol, T.untyped]
99
- ).void
100
- end
101
64
  def initialize(diagnostics, context, key, step, tags = {})
102
65
  @diagnostics = diagnostics
103
66
  @context = context
@@ -115,4 +78,4 @@ module Statsig
115
78
  end
116
79
  end
117
80
  end
118
- end
81
+ end
@@ -1,7 +1,3 @@
1
- # typed: false
2
-
3
- require 'sorbet-runtime'
4
-
5
1
  ##
6
2
  # Contains the current experiment/dynamic config values from Statsig
7
3
  #
@@ -9,46 +5,28 @@ require 'sorbet-runtime'
9
5
  #
10
6
  # Experiments Documentation: https://docs.statsig.com/experiments-plus
11
7
  class DynamicConfig
12
- extend T::Sig
13
8
 
14
- sig { returns(String) }
15
9
  attr_accessor :name
16
10
 
17
- sig { returns(T::Hash[String, T.untyped]) }
18
11
  attr_accessor :value
19
12
 
20
- sig { returns(String) }
21
13
  attr_accessor :rule_id
22
14
 
23
- sig { returns(T.nilable(String)) }
24
15
  attr_accessor :group_name
25
16
 
26
- sig { returns(String) }
27
17
  attr_accessor :id_type
28
18
 
29
- sig { returns(T.nilable(Statsig::EvaluationDetails)) }
30
19
  attr_accessor :evaluation_details
31
20
 
32
- sig do
33
- params(
34
- name: String,
35
- value: T::Hash[String, T.untyped],
36
- rule_id: String,
37
- group_name: T.nilable(String),
38
- id_type: String,
39
- evaluation_details: T.nilable(Statsig::EvaluationDetails)
40
- ).void
41
- end
42
21
  def initialize(name, value = {}, rule_id = '', group_name = nil, id_type = '', evaluation_details = nil)
43
22
  @name = name
44
- @value = value
23
+ @value = value || {}
45
24
  @rule_id = rule_id
46
25
  @group_name = group_name
47
26
  @id_type = id_type
48
27
  @evaluation_details = evaluation_details
49
28
  end
50
29
 
51
- sig { params(index: String, default_value: T.untyped).returns(T.untyped) }
52
30
  ##
53
31
  # Get the value for the given key (index), falling back to the default_value if it cannot be found.
54
32
  #
@@ -59,7 +37,6 @@ class DynamicConfig
59
37
  @value[index]
60
38
  end
61
39
 
62
- sig { params(index: String, default_value: T.untyped).returns(T.untyped) }
63
40
  ##
64
41
  # Get the value for the given key (index), falling back to the default_value if it cannot be found
65
42
  # or is found to have a different type from the default_value.
@@ -1,15 +1,10 @@
1
- # typed: true
2
-
3
1
  require 'statsig_errors'
4
- require 'sorbet-runtime'
5
2
 
6
3
  $endpoint = 'https://statsigapi.net/v1/sdk_exception'
7
4
 
8
5
  module Statsig
9
6
  class ErrorBoundary
10
- extend T::Sig
11
7
 
12
- sig { params(sdk_key: String).void }
13
8
  def initialize(sdk_key)
14
9
  @sdk_key = sdk_key
15
10
  @seen = Set.new