statsig 1.29.0 → 1.30.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 +4 -4
- data/lib/config_result.rb +10 -3
- data/lib/error_boundary.rb +2 -0
- data/lib/evaluator.rb +28 -10
- data/lib/feature_gate.rb +70 -0
- data/lib/network.rb +1 -0
- data/lib/spec_store.rb +20 -1
- data/lib/statsig.rb +64 -1
- data/lib/statsig_driver.rb +82 -18
- data/lib/statsig_errors.rb +6 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72119a11268473774b98457f89017155813cdaab4c19b8f07e1aad370ae6dd17
|
4
|
+
data.tar.gz: 69cb96c04c6b9c322bb239332b8c406a6b543bb42b0cab6da9e641d44fa15371
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d75c0a0d9c6529843c554d05b3ae49e6d863cd01da11f932e679bddddffab4287ef036af37c3cd8fff9310c10cd6758bc6e5435f78626245c5d1f315b91e09eb
|
7
|
+
data.tar.gz: b9886d0b78d1491393cfacdea4c1f4cdeae1d2a993a0f5a0875011be1083bb63e4a7721fb3a007869eaa7eaf69ad300438d8038c099e88277958d4daf6d226f7
|
data/lib/config_result.rb
CHANGED
@@ -18,6 +18,7 @@ module Statsig
|
|
18
18
|
attr_accessor :evaluation_details
|
19
19
|
attr_accessor :group_name
|
20
20
|
attr_accessor :id_type
|
21
|
+
attr_accessor :target_app_ids
|
21
22
|
|
22
23
|
def initialize(
|
23
24
|
name,
|
@@ -30,7 +31,8 @@ module Statsig
|
|
30
31
|
is_experiment_group: false,
|
31
32
|
evaluation_details: nil,
|
32
33
|
group_name: nil,
|
33
|
-
id_type: ''
|
34
|
+
id_type: '',
|
35
|
+
target_app_ids: nil)
|
34
36
|
@name = name
|
35
37
|
@gate_value = gate_value
|
36
38
|
@json_value = json_value
|
@@ -43,6 +45,7 @@ module Statsig
|
|
43
45
|
@evaluation_details = evaluation_details
|
44
46
|
@group_name = group_name
|
45
47
|
@id_type = id_type
|
48
|
+
@target_app_ids = target_app_ids
|
46
49
|
end
|
47
50
|
|
48
51
|
sig { params(config_name: String, user_persisted_values: UserPersistedValues).returns(T.nilable(ConfigResult)) }
|
@@ -62,7 +65,9 @@ module Statsig
|
|
62
65
|
hash['rule_id'],
|
63
66
|
hash['secondary_exposures'],
|
64
67
|
evaluation_details: EvaluationDetails.persisted(hash['config_sync_time'], hash['init_time']),
|
65
|
-
group_name: hash['group_name']
|
68
|
+
group_name: hash['group_name'],
|
69
|
+
id_type: hash['id_type'],
|
70
|
+
target_app_ids: hash['target_app_ids']
|
66
71
|
)
|
67
72
|
end
|
68
73
|
|
@@ -75,7 +80,9 @@ module Statsig
|
|
75
80
|
secondary_exposures: @secondary_exposures,
|
76
81
|
config_sync_time: @evaluation_details.config_sync_time,
|
77
82
|
init_time: @init_time,
|
78
|
-
group_name: @group_name
|
83
|
+
group_name: @group_name,
|
84
|
+
id_type: @id_type,
|
85
|
+
target_app_ids: @target_app_ids
|
79
86
|
}
|
80
87
|
end
|
81
88
|
end
|
data/lib/error_boundary.rb
CHANGED
@@ -24,6 +24,7 @@ module Statsig
|
|
24
24
|
end
|
25
25
|
|
26
26
|
puts '[Statsig]: An unexpected exception occurred.'
|
27
|
+
puts e.message
|
27
28
|
log_exception(e, tag: caller)
|
28
29
|
res = recover.call
|
29
30
|
end
|
@@ -45,6 +46,7 @@ module Statsig
|
|
45
46
|
'STATSIG-API-KEY' => @sdk_key,
|
46
47
|
'STATSIG-SDK-TYPE' => meta['sdkType'],
|
47
48
|
'STATSIG-SDK-VERSION' => meta['sdkVersion'],
|
49
|
+
'STATSIG-SDK-LANGUAGE-VERSION' => meta['languageVersion'],
|
48
50
|
'Content-Type' => 'application/json; charset=UTF-8'
|
49
51
|
}).accept(:json)
|
50
52
|
body = {
|
data/lib/evaluator.rb
CHANGED
@@ -31,20 +31,16 @@ module Statsig
|
|
31
31
|
|
32
32
|
sig do
|
33
33
|
params(
|
34
|
-
|
34
|
+
store: SpecStore,
|
35
35
|
options: StatsigOptions,
|
36
|
-
error_callback: T.any(Method, Proc, NilClass),
|
37
|
-
diagnostics: Diagnostics,
|
38
|
-
error_boundary: ErrorBoundary,
|
39
|
-
logger: StatsigLogger,
|
40
36
|
persistent_storage_utils: UserPersistentStorageUtils,
|
41
37
|
).void
|
42
38
|
end
|
43
|
-
def initialize(
|
44
|
-
@spec_store = Statsig::SpecStore.new(network, options, error_callback, diagnostics, error_boundary, logger)
|
39
|
+
def initialize(store, options, persistent_storage_utils)
|
45
40
|
UAParser.initialize_async
|
46
41
|
CountryLookup.initialize_async
|
47
42
|
|
43
|
+
@spec_store = store
|
48
44
|
@gate_overrides = {}
|
49
45
|
@config_overrides = {}
|
50
46
|
@options = options
|
@@ -122,7 +118,7 @@ module Statsig
|
|
122
118
|
@persistent_storage_utils.add_evaluation_to_user_persisted_values(user_persisted_values, config_name, evaluation)
|
123
119
|
@persistent_storage_utils.save_to_storage(user, config['idType'], user_persisted_values)
|
124
120
|
end
|
125
|
-
|
121
|
+
# Otherwise, remove from persisted storage
|
126
122
|
else
|
127
123
|
@persistent_storage_utils.remove_experiment_from_storage(user, config['idType'], config_name)
|
128
124
|
evaluation = eval_spec(user, config)
|
@@ -143,6 +139,26 @@ module Statsig
|
|
143
139
|
eval_spec(user, @spec_store.get_layer(layer_name))
|
144
140
|
end
|
145
141
|
|
142
|
+
def list_gates
|
143
|
+
@spec_store.gates.map { |name, _| name }
|
144
|
+
end
|
145
|
+
|
146
|
+
def list_configs
|
147
|
+
@spec_store.configs.map { |name, config| name if config['entity'] == 'dynamic_config' }.compact
|
148
|
+
end
|
149
|
+
|
150
|
+
def list_experiments
|
151
|
+
@spec_store.configs.map { |name, config| name if config['entity'] == 'experiment' }.compact
|
152
|
+
end
|
153
|
+
|
154
|
+
def list_autotunes
|
155
|
+
@spec_store.configs.map { |name, config| name if config['entity'] == 'autotune' }.compact
|
156
|
+
end
|
157
|
+
|
158
|
+
def list_layers
|
159
|
+
@spec_store.layers.map { |name, _| name }
|
160
|
+
end
|
161
|
+
|
146
162
|
def get_client_initialize_response(user, hash, client_sdk_key)
|
147
163
|
if @spec_store.is_ready_for_checks == false
|
148
164
|
return nil
|
@@ -226,7 +242,8 @@ module Statsig
|
|
226
242
|
),
|
227
243
|
is_experiment_group: result.is_experiment_group,
|
228
244
|
group_name: result.group_name,
|
229
|
-
id_type: config['idType']
|
245
|
+
id_type: config['idType'],
|
246
|
+
target_app_ids: config['targetAppIDs']
|
230
247
|
)
|
231
248
|
end
|
232
249
|
|
@@ -248,7 +265,8 @@ module Statsig
|
|
248
265
|
@spec_store.init_reason
|
249
266
|
),
|
250
267
|
group_name: nil,
|
251
|
-
id_type: config['idType']
|
268
|
+
id_type: config['idType'],
|
269
|
+
target_app_ids: config['targetAppIDs']
|
252
270
|
)
|
253
271
|
end
|
254
272
|
|
data/lib/feature_gate.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# typed: false
|
2
|
+
|
3
|
+
require 'sorbet-runtime'
|
4
|
+
|
5
|
+
class FeatureGate
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
sig { returns(String) }
|
9
|
+
attr_accessor :name
|
10
|
+
|
11
|
+
sig { returns(T::Boolean) }
|
12
|
+
attr_accessor :value
|
13
|
+
|
14
|
+
sig { returns(String) }
|
15
|
+
attr_accessor :rule_id
|
16
|
+
|
17
|
+
sig { returns(T.nilable(String)) }
|
18
|
+
attr_accessor :group_name
|
19
|
+
|
20
|
+
sig { returns(String) }
|
21
|
+
attr_accessor :id_type
|
22
|
+
|
23
|
+
sig { returns(T.nilable(Statsig::EvaluationDetails)) }
|
24
|
+
attr_accessor :evaluation_details
|
25
|
+
|
26
|
+
sig { returns(T.nilable(T::Array[String])) }
|
27
|
+
attr_accessor :target_app_ids
|
28
|
+
|
29
|
+
sig do
|
30
|
+
params(
|
31
|
+
name: String,
|
32
|
+
value: T::Boolean,
|
33
|
+
rule_id: String,
|
34
|
+
group_name: T.nilable(String),
|
35
|
+
id_type: String,
|
36
|
+
evaluation_details: T.nilable(Statsig::EvaluationDetails),
|
37
|
+
target_app_ids: T.nilable(T::Array[String])
|
38
|
+
).void
|
39
|
+
end
|
40
|
+
def initialize(
|
41
|
+
name,
|
42
|
+
value: false,
|
43
|
+
rule_id: '',
|
44
|
+
group_name: nil,
|
45
|
+
id_type: '',
|
46
|
+
evaluation_details: nil,
|
47
|
+
target_app_ids: nil
|
48
|
+
)
|
49
|
+
@name = name
|
50
|
+
@value = value
|
51
|
+
@rule_id = rule_id
|
52
|
+
@group_name = group_name
|
53
|
+
@id_type = id_type
|
54
|
+
@evaluation_details = evaluation_details
|
55
|
+
@target_app_ids = target_app_ids
|
56
|
+
end
|
57
|
+
|
58
|
+
sig { params(res: Statsig::ConfigResult).returns(FeatureGate) }
|
59
|
+
def self.from_config_result(res)
|
60
|
+
new(
|
61
|
+
res.name,
|
62
|
+
value: res.gate_value,
|
63
|
+
rule_id: res.rule_id,
|
64
|
+
group_name: res.group_name,
|
65
|
+
id_type: res.id_type,
|
66
|
+
evaluation_details: res.evaluation_details,
|
67
|
+
target_app_ids: res.target_app_ids
|
68
|
+
)
|
69
|
+
end
|
70
|
+
end
|
data/lib/network.rb
CHANGED
@@ -42,6 +42,7 @@ module Statsig
|
|
42
42
|
'Content-Type' => 'application/json; charset=UTF-8',
|
43
43
|
'STATSIG-SDK-TYPE' => meta['sdkType'],
|
44
44
|
'STATSIG-SDK-VERSION' => meta['sdkVersion'],
|
45
|
+
'STATSIG-SDK-LANGUAGE-VERSION' => meta['languageVersion'],
|
45
46
|
'Accept-Encoding' => 'gzip'
|
46
47
|
}
|
47
48
|
).accept(:json)
|
data/lib/spec_store.rb
CHANGED
@@ -13,7 +13,7 @@ module Statsig
|
|
13
13
|
attr_accessor :initial_config_sync_time
|
14
14
|
attr_accessor :init_reason
|
15
15
|
|
16
|
-
def initialize(network, options, error_callback, diagnostics, error_boundary, logger)
|
16
|
+
def initialize(network, options, error_callback, diagnostics, error_boundary, logger, secret_key)
|
17
17
|
@init_reason = EvaluationReason::UNINITIALIZED
|
18
18
|
@network = network
|
19
19
|
@options = options
|
@@ -35,6 +35,7 @@ module Statsig
|
|
35
35
|
@diagnostics = diagnostics
|
36
36
|
@error_boundary = error_boundary
|
37
37
|
@logger = logger
|
38
|
+
@secret_key = secret_key
|
38
39
|
|
39
40
|
@id_list_thread_pool = Concurrent::FixedThreadPool.new(
|
40
41
|
options.idlist_threadpool_size,
|
@@ -121,6 +122,18 @@ module Statsig
|
|
121
122
|
@specs[:layers][layer_name]
|
122
123
|
end
|
123
124
|
|
125
|
+
def gates
|
126
|
+
@specs[:gates]
|
127
|
+
end
|
128
|
+
|
129
|
+
def configs
|
130
|
+
@specs[:configs]
|
131
|
+
end
|
132
|
+
|
133
|
+
def layers
|
134
|
+
@specs[:layers]
|
135
|
+
end
|
136
|
+
|
124
137
|
def get_id_list(list_name)
|
125
138
|
@specs[:id_lists][list_name]
|
126
139
|
end
|
@@ -276,6 +289,12 @@ module Statsig
|
|
276
289
|
specs_json = JSON.parse(specs_string)
|
277
290
|
return false unless specs_json.is_a? Hash
|
278
291
|
|
292
|
+
hashed_sdk_key_used = specs_json['hashed_sdk_key_used']
|
293
|
+
unless hashed_sdk_key_used.nil? or hashed_sdk_key_used == Statsig::HashUtils.djb2(@secret_key)
|
294
|
+
err_boundary.log_exception(Statsig::InvalidSDKKeyResponse.new)
|
295
|
+
return false
|
296
|
+
end
|
297
|
+
|
279
298
|
@last_config_sync_time = specs_json['time'] || @last_config_sync_time
|
280
299
|
return false unless specs_json['has_updates'] == true &&
|
281
300
|
!specs_json['feature_gates'].nil? &&
|
data/lib/statsig.rb
CHANGED
@@ -26,6 +26,23 @@ module Statsig
|
|
26
26
|
@shared_instance = StatsigDriver.new(secret_key, options, error_callback)
|
27
27
|
end
|
28
28
|
|
29
|
+
class GetGateOptions < T::Struct
|
30
|
+
prop :disable_log_exposure, T::Boolean, default: false
|
31
|
+
prop :skip_evaluation, T::Boolean, default: false
|
32
|
+
end
|
33
|
+
|
34
|
+
sig { params(user: StatsigUser, gate_name: String, options: GetGateOptions).returns(FeatureGate) }
|
35
|
+
##
|
36
|
+
# Gets the gate, evaluated against the given user. An exposure event will automatically be logged for the gate.
|
37
|
+
#
|
38
|
+
# @param user A StatsigUser object used for the evaluation
|
39
|
+
# @param gate_name The name of the gate being checked
|
40
|
+
# @param options Additional options for evaluating the gate
|
41
|
+
def self.get_gate(user, gate_name, options = GetGateOptions.new)
|
42
|
+
ensure_initialized
|
43
|
+
@shared_instance&.get_gate(user, gate_name, options)
|
44
|
+
end
|
45
|
+
|
29
46
|
class CheckGateOptions < T::Struct
|
30
47
|
prop :disable_log_exposure, T::Boolean, default: false
|
31
48
|
end
|
@@ -212,6 +229,51 @@ module Statsig
|
|
212
229
|
@shared_instance&.manually_sync_idlists
|
213
230
|
end
|
214
231
|
|
232
|
+
sig { returns(T::Array[String]) }
|
233
|
+
##
|
234
|
+
# Returns a list of all gate names
|
235
|
+
#
|
236
|
+
def self.list_gates
|
237
|
+
ensure_initialized
|
238
|
+
@shared_instance&.list_gates
|
239
|
+
end
|
240
|
+
|
241
|
+
sig { returns(T::Array[String]) }
|
242
|
+
##
|
243
|
+
# Returns a list of all config names
|
244
|
+
#
|
245
|
+
def self.list_configs
|
246
|
+
ensure_initialized
|
247
|
+
@shared_instance&.list_configs
|
248
|
+
end
|
249
|
+
|
250
|
+
sig { returns(T::Array[String]) }
|
251
|
+
##
|
252
|
+
# Returns a list of all experiment names
|
253
|
+
#
|
254
|
+
def self.list_experiments
|
255
|
+
ensure_initialized
|
256
|
+
@shared_instance&.list_experiments
|
257
|
+
end
|
258
|
+
|
259
|
+
sig { returns(T::Array[String]) }
|
260
|
+
##
|
261
|
+
# Returns a list of all autotune names
|
262
|
+
#
|
263
|
+
def self.list_autotunes
|
264
|
+
ensure_initialized
|
265
|
+
@shared_instance&.list_autotunes
|
266
|
+
end
|
267
|
+
|
268
|
+
sig { returns(T::Array[String]) }
|
269
|
+
##
|
270
|
+
# Returns a list of all layer names
|
271
|
+
#
|
272
|
+
def self.list_layers
|
273
|
+
ensure_initialized
|
274
|
+
@shared_instance&.list_layers
|
275
|
+
end
|
276
|
+
|
215
277
|
sig { void }
|
216
278
|
##
|
217
279
|
# Stops all Statsig activity and flushes any pending events.
|
@@ -265,7 +327,8 @@ module Statsig
|
|
265
327
|
def self.get_statsig_metadata
|
266
328
|
{
|
267
329
|
'sdkType' => 'ruby-server',
|
268
|
-
'sdkVersion' => '1.
|
330
|
+
'sdkVersion' => '1.30.0',
|
331
|
+
'languageVersion' => RUBY_VERSION
|
269
332
|
}
|
270
333
|
end
|
271
334
|
|
data/lib/statsig_driver.rb
CHANGED
@@ -10,6 +10,7 @@ require 'statsig_options'
|
|
10
10
|
require 'statsig_user'
|
11
11
|
require 'spec_store'
|
12
12
|
require 'dynamic_config'
|
13
|
+
require 'feature_gate'
|
13
14
|
require 'error_boundary'
|
14
15
|
require 'layer'
|
15
16
|
require 'sorbet-runtime'
|
@@ -38,34 +39,62 @@ class StatsigDriver
|
|
38
39
|
@net = Statsig::Network.new(secret_key, @options)
|
39
40
|
@logger = Statsig::StatsigLogger.new(@net, @options, @err_boundary)
|
40
41
|
@persistent_storage_utils = Statsig::UserPersistentStorageUtils.new(@options)
|
41
|
-
@
|
42
|
+
@store = Statsig::SpecStore.new(@net, @options, error_callback, @diagnostics, @err_boundary, @logger, secret_key)
|
43
|
+
@evaluator = Statsig::Evaluator.new(@store, @options, @persistent_storage_utils)
|
42
44
|
tracker.end(success: true)
|
43
45
|
|
44
46
|
@logger.log_diagnostics_event(@diagnostics)
|
45
47
|
}, caller: __method__.to_s)
|
46
48
|
end
|
47
49
|
|
50
|
+
sig do
|
51
|
+
params(
|
52
|
+
user: StatsigUser,
|
53
|
+
gate_name: String,
|
54
|
+
disable_log_exposure: T::Boolean,
|
55
|
+
skip_evaluation: T::Boolean
|
56
|
+
).returns(FeatureGate)
|
57
|
+
end
|
58
|
+
def get_gate_impl(user, gate_name, disable_log_exposure: false, skip_evaluation: false)
|
59
|
+
if skip_evaluation
|
60
|
+
gate = @store.get_gate(gate_name)
|
61
|
+
return FeatureGate.new(gate_name) if gate.nil?
|
62
|
+
return FeatureGate.new(gate['name'], target_app_ids: gate['targetAppIDs'])
|
63
|
+
end
|
64
|
+
user = verify_inputs(user, gate_name, 'gate_name')
|
65
|
+
|
66
|
+
res = @evaluator.check_gate(user, gate_name)
|
67
|
+
if res.nil?
|
68
|
+
res = Statsig::ConfigResult.new(gate_name)
|
69
|
+
end
|
70
|
+
|
71
|
+
if res == $fetch_from_server
|
72
|
+
res = check_gate_fallback(user, gate_name)
|
73
|
+
# exposure logged by the server
|
74
|
+
else
|
75
|
+
unless disable_log_exposure
|
76
|
+
@logger.log_gate_exposure(
|
77
|
+
user, res.name, res.gate_value, res.rule_id, res.secondary_exposures, res.evaluation_details
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
FeatureGate.from_config_result(res)
|
82
|
+
end
|
83
|
+
|
84
|
+
sig { params(user: StatsigUser, gate_name: String, options: Statsig::GetGateOptions).returns(FeatureGate) }
|
85
|
+
def get_gate(user, gate_name, options = Statsig::GetGateOptions.new)
|
86
|
+
@err_boundary.capture(task: lambda {
|
87
|
+
run_with_diagnostics(task: lambda {
|
88
|
+
get_gate_impl(user, gate_name, disable_log_exposure: options.disable_log_exposure, skip_evaluation: options.skip_evaluation)
|
89
|
+
}, caller: __method__.to_s)
|
90
|
+
}, recover: -> { false }, caller: __method__.to_s)
|
91
|
+
end
|
92
|
+
|
48
93
|
sig { params(user: StatsigUser, gate_name: String, options: Statsig::CheckGateOptions).returns(T::Boolean) }
|
49
94
|
def check_gate(user, gate_name, options = Statsig::CheckGateOptions.new)
|
50
95
|
@err_boundary.capture(task: lambda {
|
51
96
|
run_with_diagnostics(task: lambda {
|
52
|
-
|
53
|
-
|
54
|
-
res = @evaluator.check_gate(user, gate_name)
|
55
|
-
if res.nil?
|
56
|
-
res = Statsig::ConfigResult.new(gate_name)
|
57
|
-
end
|
58
|
-
|
59
|
-
if res == $fetch_from_server
|
60
|
-
res = check_gate_fallback(user, gate_name)
|
61
|
-
# exposure logged by the server
|
62
|
-
else
|
63
|
-
if !options.disable_log_exposure
|
64
|
-
@logger.log_gate_exposure(user, res.name, res.gate_value, res.rule_id, res.secondary_exposures, res.evaluation_details)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
res.gate_value
|
97
|
+
get_gate_impl(user, gate_name, disable_log_exposure: options.disable_log_exposure).value
|
69
98
|
}, caller: __method__.to_s)
|
70
99
|
}, recover: -> { false }, caller: __method__.to_s)
|
71
100
|
end
|
@@ -184,6 +213,41 @@ class StatsigDriver
|
|
184
213
|
}, caller: __method__.to_s)
|
185
214
|
end
|
186
215
|
|
216
|
+
sig { returns(T::Array[String]) }
|
217
|
+
def list_gates
|
218
|
+
@err_boundary.capture(task: lambda {
|
219
|
+
@evaluator.list_gates
|
220
|
+
}, caller: __method__.to_s)
|
221
|
+
end
|
222
|
+
|
223
|
+
sig { returns(T::Array[String]) }
|
224
|
+
def list_configs
|
225
|
+
@err_boundary.capture(task: lambda {
|
226
|
+
@evaluator.list_configs
|
227
|
+
}, caller: __method__.to_s)
|
228
|
+
end
|
229
|
+
|
230
|
+
sig { returns(T::Array[String]) }
|
231
|
+
def list_experiments
|
232
|
+
@err_boundary.capture(task: lambda {
|
233
|
+
@evaluator.list_experiments
|
234
|
+
}, caller: __method__.to_s)
|
235
|
+
end
|
236
|
+
|
237
|
+
sig { returns(T::Array[String]) }
|
238
|
+
def list_autotunes
|
239
|
+
@err_boundary.capture(task: lambda {
|
240
|
+
@evaluator.list_autotunes
|
241
|
+
}, caller: __method__.to_s)
|
242
|
+
end
|
243
|
+
|
244
|
+
sig { returns(T::Array[String]) }
|
245
|
+
def list_layers
|
246
|
+
@err_boundary.capture(task: lambda {
|
247
|
+
@evaluator.list_layers
|
248
|
+
}, caller: __method__.to_s)
|
249
|
+
end
|
250
|
+
|
187
251
|
def shutdown
|
188
252
|
@err_boundary.capture(task: lambda {
|
189
253
|
@shutdown = true
|
data/lib/statsig_errors.rb
CHANGED
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.
|
4
|
+
version: 1.30.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:
|
11
|
+
date: 2024-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -330,6 +330,7 @@ files:
|
|
330
330
|
- lib/evaluation_details.rb
|
331
331
|
- lib/evaluation_helpers.rb
|
332
332
|
- lib/evaluator.rb
|
333
|
+
- lib/feature_gate.rb
|
333
334
|
- lib/hash_utils.rb
|
334
335
|
- lib/id_list.rb
|
335
336
|
- lib/interfaces/data_store.rb
|