statsig 1.34.2 → 2.0.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/api_config.rb +0 -141
- data/lib/client_initialize_helpers.rb +21 -20
- data/lib/constants.rb +65 -0
- data/lib/dynamic_config.rb +13 -5
- data/lib/evaluation_helpers.rb +16 -5
- data/lib/evaluator.rb +146 -116
- data/lib/interfaces/data_store.rb +1 -1
- data/lib/layer.rb +12 -5
- data/lib/memo.rb +8 -6
- data/lib/network.rb +41 -28
- data/lib/spec_store.rb +39 -47
- data/lib/statsig.rb +1 -1
- data/lib/statsig_driver.rb +11 -6
- data/lib/statsig_options.rb +19 -10
- metadata +16 -3
- data/lib/uri_helper.rb +0 -29
    
        data/lib/network.rb
    CHANGED
    
    | @@ -3,7 +3,6 @@ require 'json' | |
| 3 3 | 
             
            require 'securerandom'
         | 
| 4 4 | 
             
            require 'zlib'
         | 
| 5 5 |  | 
| 6 | 
            -
            require 'uri_helper'
         | 
| 7 6 | 
             
            require 'connection_pool'
         | 
| 8 7 |  | 
| 9 8 | 
             
            RETRY_CODES = [408, 500, 502, 503, 504, 522, 524, 599].freeze
         | 
| @@ -22,7 +21,7 @@ module Statsig | |
| 22 21 |  | 
| 23 22 | 
             
                def initialize(server_secret, options, backoff_mult = 10)
         | 
| 24 23 | 
             
                  super()
         | 
| 25 | 
            -
                   | 
| 24 | 
            +
                  @options = options
         | 
| 26 25 | 
             
                  @server_secret = server_secret
         | 
| 27 26 | 
             
                  @local_mode = options.local_mode
         | 
| 28 27 | 
             
                  @timeout = options.network_timeout
         | 
| @@ -43,6 +42,7 @@ module Statsig | |
| 43 42 | 
             
                        'Accept-Encoding' => 'gzip'
         | 
| 44 43 | 
             
                      }
         | 
| 45 44 | 
             
                    ).accept(:json)
         | 
| 45 | 
            +
             | 
| 46 46 | 
             
                    if @timeout
         | 
| 47 47 | 
             
                      client = client.timeout(@timeout)
         | 
| 48 48 | 
             
                    end
         | 
| @@ -52,18 +52,42 @@ module Statsig | |
| 52 52 | 
             
                end
         | 
| 53 53 |  | 
| 54 54 | 
             
                def download_config_specs(since_time)
         | 
| 55 | 
            -
                   | 
| 55 | 
            +
                  url = @options.download_config_specs_url
         | 
| 56 | 
            +
                  get("#{url}#{@server_secret}.json?sinceTime=#{since_time}")
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                def post_logs(events, error_boundary)
         | 
| 60 | 
            +
                  url = @options.log_event_url
         | 
| 61 | 
            +
                  event_count = events.length
         | 
| 62 | 
            +
                  json_body = JSON.generate({ events: events, statsigMetadata: Statsig.get_statsig_metadata })
         | 
| 63 | 
            +
                  gzip = Zlib::GzipWriter.new(StringIO.new)
         | 
| 64 | 
            +
                  gzip << json_body
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  response, e = post(url, gzip.close.string, @post_logs_retry_limit, 1, true, event_count)
         | 
| 67 | 
            +
                  unless e == nil
         | 
| 68 | 
            +
                    message = "Failed to log #{event_count} events after #{@post_logs_retry_limit} retries"
         | 
| 69 | 
            +
                    puts "[Statsig]: #{message}"
         | 
| 70 | 
            +
                    error_boundary.log_exception(e, tag: 'statsig::log_event_failed', extra: { eventCount: event_count, error: message }, force: true)
         | 
| 71 | 
            +
                    return
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                rescue StandardError
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                def get_id_lists
         | 
| 78 | 
            +
                  url = @options.get_id_lists_url
         | 
| 79 | 
            +
                  post(url, JSON.generate({ 'statsigMetadata' => Statsig.get_statsig_metadata }))
         | 
| 56 80 | 
             
                end
         | 
| 57 81 |  | 
| 58 | 
            -
                def get( | 
| 59 | 
            -
                  request(:GET,  | 
| 82 | 
            +
                def get(url, retries = 0, backoff = 1)
         | 
| 83 | 
            +
                  request(:GET, url, nil, retries, backoff)
         | 
| 60 84 | 
             
                end
         | 
| 61 85 |  | 
| 62 | 
            -
                def post( | 
| 63 | 
            -
                  request(:POST,  | 
| 86 | 
            +
                def post(url, body, retries = 0, backoff = 1, zipped = false, event_count = 0)
         | 
| 87 | 
            +
                  request(:POST, url, body, retries, backoff, zipped, event_count)
         | 
| 64 88 | 
             
                end
         | 
| 65 89 |  | 
| 66 | 
            -
                def request(method,  | 
| 90 | 
            +
                def request(method, url, body, retries = 0, backoff = 1, zipped = false, event_count = 0)
         | 
| 67 91 | 
             
                  if @local_mode
         | 
| 68 92 | 
             
                    return nil, nil
         | 
| 69 93 | 
             
                  end
         | 
| @@ -75,10 +99,15 @@ module Statsig | |
| 75 99 | 
             
                      backoff_adjusted = @post_logs_retry_backoff.call(retries)
         | 
| 76 100 | 
             
                    end
         | 
| 77 101 | 
             
                  end
         | 
| 78 | 
            -
             | 
| 102 | 
            +
             | 
| 79 103 | 
             
                  begin
         | 
| 80 104 | 
             
                    res = @connection_pool.with do |conn|
         | 
| 81 | 
            -
                      request = conn.headers( | 
| 105 | 
            +
                      request = conn.headers(
         | 
| 106 | 
            +
                        'STATSIG-CLIENT-TIME' => (Time.now.to_f * 1000).to_i.to_s,
         | 
| 107 | 
            +
                        'CONTENT-ENCODING' => zipped ? 'gzip' : nil,
         | 
| 108 | 
            +
                        'STATSIG-EVENT-COUNT' => event_count == 0 ? nil : event_count.to_s
         | 
| 109 | 
            +
                      )
         | 
| 110 | 
            +
             | 
| 82 111 | 
             
                      case method
         | 
| 83 112 | 
             
                      when :GET
         | 
| 84 113 | 
             
                        request.get(url)
         | 
| @@ -91,7 +120,7 @@ module Statsig | |
| 91 120 | 
             
                    return nil, e unless retries.positive?
         | 
| 92 121 |  | 
| 93 122 | 
             
                    sleep backoff_adjusted
         | 
| 94 | 
            -
                    return request(method,  | 
| 123 | 
            +
                    return request(method, url, body, retries - 1, backoff * @backoff_multiplier, zipped, event_count)
         | 
| 95 124 | 
             
                  end
         | 
| 96 125 | 
             
                  return res, nil if res.status.success?
         | 
| 97 126 |  | 
| @@ -102,23 +131,7 @@ module Statsig | |
| 102 131 |  | 
| 103 132 | 
             
                  ## status code retry
         | 
| 104 133 | 
             
                  sleep backoff_adjusted
         | 
| 105 | 
            -
                  request(method,  | 
| 106 | 
            -
                end
         | 
| 107 | 
            -
             | 
| 108 | 
            -
                def post_logs(events, error_boundary)
         | 
| 109 | 
            -
                  event_count = events.length
         | 
| 110 | 
            -
                  json_body = JSON.generate({ events: events, statsigMetadata: Statsig.get_statsig_metadata })
         | 
| 111 | 
            -
                  gzip = Zlib::GzipWriter.new(StringIO.new)
         | 
| 112 | 
            -
                  gzip << json_body
         | 
| 113 | 
            -
                  response, e = post('log_event', gzip.close.string, @post_logs_retry_limit, 1, true, event_count)
         | 
| 114 | 
            -
                  unless e == nil
         | 
| 115 | 
            -
                    message = "Failed to log #{event_count} events after #{@post_logs_retry_limit} retries"
         | 
| 116 | 
            -
                    puts "[Statsig]: #{message}"
         | 
| 117 | 
            -
                    error_boundary.log_exception(e, tag: 'statsig::log_event_failed', extra: { eventCount: event_count, error: message }, force: true)
         | 
| 118 | 
            -
                    return
         | 
| 119 | 
            -
                  end
         | 
| 120 | 
            -
                rescue StandardError
         | 
| 121 | 
            -
             | 
| 134 | 
            +
                  request(method, url, body, retries - 1, backoff * @backoff_multiplier, zipped, event_count)
         | 
| 122 135 | 
             
                end
         | 
| 123 136 | 
             
              end
         | 
| 124 137 | 
             
            end
         | 
    
        data/lib/spec_store.rb
    CHANGED
    
    | @@ -33,6 +33,7 @@ module Statsig | |
| 33 33 | 
             
                  @gates = {}
         | 
| 34 34 | 
             
                  @configs = {}
         | 
| 35 35 | 
             
                  @layers = {}
         | 
| 36 | 
            +
                  @condition_map = {}
         | 
| 36 37 | 
             
                  @id_lists = {}
         | 
| 37 38 | 
             
                  @experiment_to_layer = {}
         | 
| 38 39 | 
             
                  @sdk_keys_to_app_ids = {}
         | 
| @@ -102,33 +103,39 @@ module Statsig | |
| 102 103 | 
             
                end
         | 
| 103 104 |  | 
| 104 105 | 
             
                def has_gate?(gate_name)
         | 
| 105 | 
            -
                  @gates.key?(gate_name)
         | 
| 106 | 
            +
                  @gates.key?(gate_name.to_sym)
         | 
| 106 107 | 
             
                end
         | 
| 107 108 |  | 
| 108 109 | 
             
                def has_config?(config_name)
         | 
| 109 | 
            -
                  @configs.key?(config_name)
         | 
| 110 | 
            +
                  @configs.key?(config_name.to_sym)
         | 
| 110 111 | 
             
                end
         | 
| 111 112 |  | 
| 112 113 | 
             
                def has_layer?(layer_name)
         | 
| 113 | 
            -
                  @layers.key?(layer_name)
         | 
| 114 | 
            +
                  @layers.key?(layer_name.to_sym)
         | 
| 114 115 | 
             
                end
         | 
| 115 116 |  | 
| 116 117 | 
             
                def get_gate(gate_name)
         | 
| 117 | 
            -
                   | 
| 118 | 
            -
             | 
| 119 | 
            -
                  @gates[ | 
| 118 | 
            +
                  gate_sym = gate_name.to_sym
         | 
| 119 | 
            +
                  return nil unless has_gate?(gate_sym)
         | 
| 120 | 
            +
                  @gates[gate_sym]
         | 
| 120 121 | 
             
                end
         | 
| 121 122 |  | 
| 122 123 | 
             
                def get_config(config_name)
         | 
| 123 | 
            -
                   | 
| 124 | 
            +
                  config_sym = config_name.to_sym
         | 
| 125 | 
            +
                  return nil unless has_config?(config_sym)
         | 
| 124 126 |  | 
| 125 | 
            -
                  @configs[ | 
| 127 | 
            +
                  @configs[config_sym]
         | 
| 126 128 | 
             
                end
         | 
| 127 129 |  | 
| 128 130 | 
             
                def get_layer(layer_name)
         | 
| 129 | 
            -
                   | 
| 131 | 
            +
                  layer_sym = layer_name.to_sym
         | 
| 132 | 
            +
                  return nil unless has_layer?(layer_sym)
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                  @layers[layer_sym]
         | 
| 135 | 
            +
                end
         | 
| 130 136 |  | 
| 131 | 
            -
             | 
| 137 | 
            +
                def get_condition(condition_hash)
         | 
| 138 | 
            +
                  @condition_map[condition_hash.to_sym]
         | 
| 132 139 | 
             
                end
         | 
| 133 140 |  | 
| 134 141 | 
             
                def get_id_list(list_name)
         | 
| @@ -169,7 +176,7 @@ module Statsig | |
| 169 176 | 
             
                end
         | 
| 170 177 |  | 
| 171 178 | 
             
                def sync_config_specs
         | 
| 172 | 
            -
                  if @options.data_store&.should_be_used_for_querying_updates(Interfaces::IDataStore:: | 
| 179 | 
            +
                  if @options.data_store&.should_be_used_for_querying_updates(Interfaces::IDataStore::CONFIG_SPECS_V2_KEY)
         | 
| 173 180 | 
             
                    load_config_specs_from_storage_adapter('config_sync')
         | 
| 174 181 | 
             
                  else
         | 
| 175 182 | 
             
                    download_config_specs('config_sync')
         | 
| @@ -190,7 +197,7 @@ module Statsig | |
| 190 197 |  | 
| 191 198 | 
             
                def load_config_specs_from_storage_adapter(context)
         | 
| 192 199 | 
             
                  tracker = @diagnostics.track(context, 'data_store_config_specs', 'fetch')
         | 
| 193 | 
            -
                  cached_values = @options.data_store.get(Interfaces::IDataStore:: | 
| 200 | 
            +
                  cached_values = @options.data_store.get(Interfaces::IDataStore::CONFIG_SPECS_V2_KEY)
         | 
| 194 201 | 
             
                  tracker.end(success: true)
         | 
| 195 202 | 
             
                  return if cached_values.nil?
         | 
| 196 203 |  | 
| @@ -204,12 +211,12 @@ module Statsig | |
| 204 211 | 
             
                  download_config_specs(context)
         | 
| 205 212 | 
             
                end
         | 
| 206 213 |  | 
| 207 | 
            -
                def  | 
| 214 | 
            +
                def save_rulesets_to_storage_adapter(rulesets_string)
         | 
| 208 215 | 
             
                  if @options.data_store.nil?
         | 
| 209 216 | 
             
                    return
         | 
| 210 217 | 
             
                  end
         | 
| 211 218 |  | 
| 212 | 
            -
                  @options.data_store.set(Interfaces::IDataStore:: | 
| 219 | 
            +
                  @options.data_store.set(Interfaces::IDataStore::CONFIG_SPECS_V2_KEY, rulesets_string)
         | 
| 213 220 | 
             
                end
         | 
| 214 221 |  | 
| 215 222 | 
             
                def spawn_sync_config_specs_thread
         | 
| @@ -293,50 +300,35 @@ module Statsig | |
| 293 300 | 
             
                    return false
         | 
| 294 301 | 
             
                  end
         | 
| 295 302 |  | 
| 296 | 
            -
                   | 
| 297 | 
            -
                   | 
| 298 | 
            -
             | 
| 299 | 
            -
             | 
| 300 | 
            -
             | 
| 303 | 
            +
                  new_specs_sync_time = specs_json[:time]
         | 
| 304 | 
            +
                  if new_specs_sync_time.nil? \
         | 
| 305 | 
            +
                    || new_specs_sync_time < @last_config_sync_time \
         | 
| 306 | 
            +
                    || specs_json[:has_updates] != true \
         | 
| 307 | 
            +
                    || specs_json[:feature_gates].nil? \
         | 
| 308 | 
            +
                    || specs_json[:dynamic_configs].nil? \
         | 
| 309 | 
            +
                    || specs_json[:layer_configs].nil?
         | 
| 310 | 
            +
                    return false
         | 
| 311 | 
            +
                  end
         | 
| 301 312 |  | 
| 302 | 
            -
                  @ | 
| 303 | 
            -
                   | 
| 304 | 
            -
                  new_configs = process_configs(specs_json[:dynamic_configs])
         | 
| 305 | 
            -
                  new_layers = process_configs(specs_json[:layer_configs])
         | 
| 313 | 
            +
                  @last_config_sync_time = new_specs_sync_time
         | 
| 314 | 
            +
                  @unsupported_configs.clear
         | 
| 306 315 |  | 
| 307 | 
            -
                  new_exp_to_layer = {}
         | 
| 308 316 | 
             
                  specs_json[:diagnostics]&.each { |key, value| @diagnostics.sample_rates[key.to_s] = value }
         | 
| 309 317 |  | 
| 310 | 
            -
                   | 
| 311 | 
            -
             | 
| 312 | 
            -
             | 
| 313 | 
            -
             | 
| 314 | 
            -
                   | 
| 315 | 
            -
             | 
| 316 | 
            -
                  @gates = new_gates
         | 
| 317 | 
            -
                  @configs = new_configs
         | 
| 318 | 
            -
                  @layers = new_layers
         | 
| 319 | 
            -
                  @experiment_to_layer = new_exp_to_layer
         | 
| 318 | 
            +
                  @gates = specs_json[:feature_gates]
         | 
| 319 | 
            +
                  @configs = specs_json[:dynamic_configs]
         | 
| 320 | 
            +
                  @layers = specs_json[:layer_configs]
         | 
| 321 | 
            +
                  @condition_map = specs_json[:condition_map]
         | 
| 322 | 
            +
                  @experiment_to_layer = specs_json[:experiment_to_layer]
         | 
| 320 323 | 
             
                  @sdk_keys_to_app_ids = specs_json[:sdk_keys_to_app_ids] || {}
         | 
| 321 324 | 
             
                  @hashed_sdk_keys_to_app_ids = specs_json[:hashed_sdk_keys_to_app_ids] || {}
         | 
| 322 325 |  | 
| 323 326 | 
             
                  unless from_adapter
         | 
| 324 | 
            -
                     | 
| 327 | 
            +
                    save_rulesets_to_storage_adapter(specs_string)
         | 
| 325 328 | 
             
                  end
         | 
| 326 329 | 
             
                  true
         | 
| 327 330 | 
             
                end
         | 
| 328 331 |  | 
| 329 | 
            -
                def process_configs(configs)
         | 
| 330 | 
            -
                  configs.each_with_object({}) do |config, new_configs|
         | 
| 331 | 
            -
                    begin
         | 
| 332 | 
            -
                      new_configs[config[:name]] = APIConfig.from_json(config)
         | 
| 333 | 
            -
                    rescue UnsupportedConfigException => e
         | 
| 334 | 
            -
                      @unsupported_configs.add(config[:name])
         | 
| 335 | 
            -
                      nil
         | 
| 336 | 
            -
                    end
         | 
| 337 | 
            -
                  end
         | 
| 338 | 
            -
                end
         | 
| 339 | 
            -
             | 
| 340 332 | 
             
                def get_id_lists_from_adapter(context)
         | 
| 341 333 | 
             
                  tracker = @diagnostics.track(context, 'data_store_id_lists', 'fetch')
         | 
| 342 334 | 
             
                  cached_values = @options.data_store.get(Interfaces::IDataStore::ID_LISTS_KEY)
         | 
| @@ -361,7 +353,7 @@ module Statsig | |
| 361 353 |  | 
| 362 354 | 
             
                def get_id_lists_from_network(context)
         | 
| 363 355 | 
             
                  tracker = @diagnostics.track(context, 'get_id_list_sources', 'network_request')
         | 
| 364 | 
            -
                  response, e = @network. | 
| 356 | 
            +
                  response, e = @network.get_id_lists
         | 
| 365 357 | 
             
                  code = response&.status.to_i
         | 
| 366 358 | 
             
                  if e.is_a? NetworkError
         | 
| 367 359 | 
             
                    code = e.http_code
         | 
    
        data/lib/statsig.rb
    CHANGED
    
    
    
        data/lib/statsig_driver.rb
    CHANGED
    
    | @@ -54,20 +54,25 @@ class StatsigDriver | |
| 54 54 | 
             
                if skip_evaluation
         | 
| 55 55 | 
             
                  gate = @store.get_gate(gate_name)
         | 
| 56 56 | 
             
                  return FeatureGate.new(gate_name) if gate.nil?
         | 
| 57 | 
            -
                  return FeatureGate.new( | 
| 57 | 
            +
                  return FeatureGate.new(gate_name, target_app_ids: gate[:targetAppIDs])
         | 
| 58 58 | 
             
                end
         | 
| 59 59 |  | 
| 60 60 | 
             
                user = verify_inputs(user, gate_name, 'gate_name')
         | 
| 61 | 
            -
                return Statsig::Memo.for(user.get_memo(), :get_gate_impl, gate_name) do
         | 
| 62 61 |  | 
| 63 | 
            -
             | 
| 62 | 
            +
                Statsig::Memo.for(user.get_memo, :get_gate_impl, gate_name) do
         | 
| 63 | 
            +
                  res = Statsig::ConfigResult.new(
         | 
| 64 | 
            +
                    name: gate_name,
         | 
| 65 | 
            +
                    disable_exposures: disable_log_exposure,
         | 
| 66 | 
            +
                    disable_evaluation_details: disable_evaluation_details
         | 
| 67 | 
            +
                  )
         | 
| 64 68 | 
             
                  @evaluator.check_gate(user, gate_name, res, ignore_local_overrides: ignore_local_overrides)
         | 
| 65 69 |  | 
| 66 70 | 
             
                  unless disable_log_exposure
         | 
| 67 | 
            -
             | 
| 71 | 
            +
                    @logger.log_gate_exposure(
         | 
| 68 72 | 
             
                      user, res.name, res.gate_value, res.rule_id, res.secondary_exposures, res.evaluation_details
         | 
| 69 73 | 
             
                    )
         | 
| 70 74 | 
             
                  end
         | 
| 75 | 
            +
             | 
| 71 76 | 
             
                  FeatureGate.from_config_result(res)
         | 
| 72 77 | 
             
                end
         | 
| 73 78 | 
             
              end
         | 
| @@ -162,7 +167,7 @@ class StatsigDriver | |
| 162 167 | 
             
                @err_boundary.capture(caller: __method__, recover: -> { Layer.new(layer_name) }) do
         | 
| 163 168 | 
             
                  run_with_diagnostics(caller: :get_layer) do
         | 
| 164 169 | 
             
                    user = verify_inputs(user, layer_name, "layer_name")
         | 
| 165 | 
            -
                    Statsig::Memo.for(user.get_memo | 
| 170 | 
            +
                    Statsig::Memo.for(user.get_memo, :get_layer, layer_name) do
         | 
| 166 171 | 
             
                      exposures_disabled = options&.disable_log_exposure == true
         | 
| 167 172 | 
             
                      res = Statsig::ConfigResult.new(
         | 
| 168 173 | 
             
                        name: layer_name,
         | 
| @@ -367,7 +372,7 @@ class StatsigDriver | |
| 367 372 | 
             
              end
         | 
| 368 373 |  | 
| 369 374 | 
             
              def get_config_impl(user, config_name, disable_log_exposure, user_persisted_values: nil, disable_evaluation_details: false, ignore_local_overrides: false)
         | 
| 370 | 
            -
                 | 
| 375 | 
            +
                Statsig::Memo.for(user.get_memo, :get_config_impl, config_name) do
         | 
| 371 376 | 
             
                  res = Statsig::ConfigResult.new(
         | 
| 372 377 | 
             
                    name: config_name,
         | 
| 373 378 | 
             
                    disable_exposures: disable_log_exposure,
         | 
    
        data/lib/statsig_options.rb
    CHANGED
    
    | @@ -10,13 +10,14 @@ class StatsigOptions | |
| 10 10 | 
             
              # eg. { "tier" => "development" }
         | 
| 11 11 | 
             
              attr_accessor :environment
         | 
| 12 12 |  | 
| 13 | 
            -
              # The  | 
| 14 | 
            -
               | 
| 15 | 
            -
              attr_accessor :api_url_base
         | 
| 13 | 
            +
              # The url used specifically to call download_config_specs.
         | 
| 14 | 
            +
              attr_accessor :download_config_specs_url
         | 
| 16 15 |  | 
| 17 | 
            -
              # The  | 
| 18 | 
            -
               | 
| 19 | 
            -
             | 
| 16 | 
            +
              # The url used specifically to call log_event.
         | 
| 17 | 
            +
              attr_accessor :log_event_url
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              # The url used specifically to call get_id_lists.
         | 
| 20 | 
            +
              attr_accessor :get_id_lists_url
         | 
| 20 21 |  | 
| 21 22 | 
             
              # The interval (in seconds) to poll for changes to your Statsig configuration
         | 
| 22 23 | 
             
              # default: 10s
         | 
| @@ -89,8 +90,9 @@ class StatsigOptions | |
| 89 90 |  | 
| 90 91 | 
             
              def initialize(
         | 
| 91 92 | 
             
                environment = nil,
         | 
| 92 | 
            -
                 | 
| 93 | 
            -
                 | 
| 93 | 
            +
                download_config_specs_url: nil,
         | 
| 94 | 
            +
                log_event_url: nil,
         | 
| 95 | 
            +
                get_id_lists_url: nil,
         | 
| 94 96 | 
             
                rulesets_sync_interval: 10,
         | 
| 95 97 | 
             
                idlists_sync_interval: 60,
         | 
| 96 98 | 
             
                disable_rulesets_sync: false,
         | 
| @@ -111,8 +113,15 @@ class StatsigOptions | |
| 111 113 | 
             
                user_persistent_storage: nil
         | 
| 112 114 | 
             
              )
         | 
| 113 115 | 
             
                @environment = environment.is_a?(Hash) ? environment : nil
         | 
| 114 | 
            -
             | 
| 115 | 
            -
                 | 
| 116 | 
            +
             | 
| 117 | 
            +
                dcs_url = download_config_specs_url || 'https://api.statsigcdn.com/v2/download_config_specs/'
         | 
| 118 | 
            +
                unless dcs_url.end_with?('/')
         | 
| 119 | 
            +
                  dcs_url += '/'
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
                @download_config_specs_url = dcs_url
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                @log_event_url = log_event_url || 'https://statsigapi.net/v1/log_event'
         | 
| 124 | 
            +
                @get_id_lists_url = get_id_lists_url || 'https://statsigapi.net/v1/get_id_lists'
         | 
| 116 125 | 
             
                @rulesets_sync_interval = rulesets_sync_interval
         | 
| 117 126 | 
             
                @idlists_sync_interval = idlists_sync_interval
         | 
| 118 127 | 
             
                @disable_rulesets_sync = disable_rulesets_sync
         | 
    
        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:  | 
| 4 | 
            +
              version: 2.0.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- | 
| 11 | 
            +
            date: 2024-08-01 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -94,6 +94,20 @@ dependencies: | |
| 94 94 | 
             
                - - "~>"
         | 
| 95 95 | 
             
                  - !ruby/object:Gem::Version
         | 
| 96 96 | 
             
                    version: '1.0'
         | 
| 97 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 98 | 
            +
              name: mutex_m
         | 
| 99 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 100 | 
            +
                requirements:
         | 
| 101 | 
            +
                - - "~>"
         | 
| 102 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 103 | 
            +
                    version: 0.2.0
         | 
| 104 | 
            +
              type: :development
         | 
| 105 | 
            +
              prerelease: false
         | 
| 106 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 107 | 
            +
                requirements:
         | 
| 108 | 
            +
                - - "~>"
         | 
| 109 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 110 | 
            +
                    version: 0.2.0
         | 
| 97 111 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 98 112 | 
             
              name: tapioca
         | 
| 99 113 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -335,7 +349,6 @@ files: | |
| 335 349 | 
             
            - lib/statsig_options.rb
         | 
| 336 350 | 
             
            - lib/statsig_user.rb
         | 
| 337 351 | 
             
            - lib/ua_parser.rb
         | 
| 338 | 
            -
            - lib/uri_helper.rb
         | 
| 339 352 | 
             
            - lib/user_persistent_storage_utils.rb
         | 
| 340 353 | 
             
            homepage: https://rubygems.org/gems/statsig
         | 
| 341 354 | 
             
            licenses:
         | 
    
        data/lib/uri_helper.rb
    DELETED
    
    | @@ -1,29 +0,0 @@ | |
| 1 | 
            -
            class URIHelper
         | 
| 2 | 
            -
              class URIBuilder
         | 
| 3 | 
            -
             | 
| 4 | 
            -
                attr_accessor :options
         | 
| 5 | 
            -
             | 
| 6 | 
            -
                def initialize(options)
         | 
| 7 | 
            -
                  @options = options
         | 
| 8 | 
            -
                end
         | 
| 9 | 
            -
             | 
| 10 | 
            -
                def build_url(endpoint)
         | 
| 11 | 
            -
                  api = @options.api_url_base
         | 
| 12 | 
            -
                  if endpoint.include?('download_config_specs')
         | 
| 13 | 
            -
                    api = @options.api_url_download_config_specs
         | 
| 14 | 
            -
                  end
         | 
| 15 | 
            -
                  unless api.end_with?('/')
         | 
| 16 | 
            -
                    api += '/'
         | 
| 17 | 
            -
                  end
         | 
| 18 | 
            -
                  "#{api}#{endpoint}"
         | 
| 19 | 
            -
                end
         | 
| 20 | 
            -
              end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
              def self.initialize(options)
         | 
| 23 | 
            -
                @uri_builder = URIBuilder.new(options)
         | 
| 24 | 
            -
              end
         | 
| 25 | 
            -
             | 
| 26 | 
            -
              def self.build_url(endpoint)
         | 
| 27 | 
            -
                @uri_builder.build_url(endpoint)
         | 
| 28 | 
            -
              end
         | 
| 29 | 
            -
            end
         |