rox-rollout 4.1.0 → 5.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.
Files changed (121) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +51 -23
  3. data/.editorconfig +12 -0
  4. data/.github/workflows/ruby.yml +20 -0
  5. data/.gitignore +2 -0
  6. data/.rubocop.yml +17 -0
  7. data/Gemfile +2 -2
  8. data/README.md +32 -0
  9. data/Rakefile +12 -9
  10. data/bin/console +3 -4
  11. data/e2e-server/run_server.sh +12 -0
  12. data/e2e-server/server.rb +158 -0
  13. data/e2e/container.rb +11 -14
  14. data/e2e/custom_props.rb +9 -9
  15. data/e2e/rox_e2e_test.rb +18 -20
  16. data/e2e/test_vars.rb +3 -6
  17. data/example/local.rb +40 -0
  18. data/lib/rox/core/analytics.rb +18 -0
  19. data/lib/rox/core/client/buid.rb +9 -44
  20. data/lib/rox/core/client/device_properties.rb +8 -2
  21. data/lib/rox/core/client/dynamic_api.rb +53 -15
  22. data/lib/rox/core/client/internal_flags.rb +14 -2
  23. data/lib/rox/core/client/sdk_settings.rb +1 -1
  24. data/lib/rox/core/configuration/configuration.rb +1 -1
  25. data/lib/rox/core/configuration/configuration_fetched_args.rb +2 -2
  26. data/lib/rox/core/configuration/configuration_fetched_invoker.rb +8 -3
  27. data/lib/rox/core/configuration/configuration_parser.rb +39 -38
  28. data/lib/rox/core/configuration/fetcher_error.rb +1 -1
  29. data/lib/rox/core/configuration/fetcher_status.rb +1 -1
  30. data/lib/rox/core/configuration/models/experiment_model.rb +1 -1
  31. data/lib/rox/core/configuration/models/target_group_model.rb +1 -1
  32. data/lib/rox/core/consts/build.rb +3 -3
  33. data/lib/rox/core/consts/environment.rb +34 -10
  34. data/lib/rox/core/consts/property_type.rb +18 -17
  35. data/lib/rox/core/context/merged_context.rb +2 -1
  36. data/lib/rox/core/core.rb +101 -33
  37. data/lib/rox/core/entities/default_flag_values.rb +10 -0
  38. data/lib/rox/core/entities/flag.rb +22 -7
  39. data/lib/rox/core/entities/flag_setter.rb +6 -6
  40. data/lib/rox/core/entities/rox_double.rb +11 -0
  41. data/lib/rox/core/entities/rox_int.rb +11 -0
  42. data/lib/rox/core/entities/{variant.rb → rox_string.rb} +20 -13
  43. data/lib/rox/core/error_handling/exception_trigger.rb +10 -0
  44. data/lib/rox/core/error_handling/userspace_handler_exception.rb +12 -0
  45. data/lib/rox/core/error_handling/userspace_unhandled_error_invoker.rb +41 -0
  46. data/lib/rox/core/impression/impression_args.rb +2 -2
  47. data/lib/rox/core/impression/impression_invoker.rb +41 -7
  48. data/lib/rox/core/impression/models/experiment.rb +1 -1
  49. data/lib/rox/core/impression/models/reporting_value.rb +10 -2
  50. data/lib/rox/core/logging/logging.rb +3 -3
  51. data/lib/rox/core/logging/no_op_logger.rb +1 -1
  52. data/lib/rox/core/network/configuration_fetch_result.rb +1 -1
  53. data/lib/rox/core/network/configuration_fetcher.rb +9 -8
  54. data/lib/rox/core/network/configuration_fetcher_base.rb +1 -1
  55. data/lib/rox/core/network/configuration_fetcher_roxy.rb +4 -4
  56. data/lib/rox/core/network/configuration_fetcher_self_managed.rb +30 -0
  57. data/lib/rox/core/network/configuration_source.rb +1 -1
  58. data/lib/rox/core/network/request.rb +3 -3
  59. data/lib/rox/core/network/request_configuration_builder.rb +12 -9
  60. data/lib/rox/core/network/request_data.rb +1 -1
  61. data/lib/rox/core/network/response.rb +20 -4
  62. data/lib/rox/core/network/state_sender.rb +146 -0
  63. data/lib/rox/core/notifications/notification_listener.rb +4 -4
  64. data/lib/rox/core/properties/custom_property.rb +1 -1
  65. data/lib/rox/core/properties/custom_property_type.rb +1 -1
  66. data/lib/rox/core/properties/device_property.rb +2 -2
  67. data/lib/rox/core/properties/property_factory.rb +132 -0
  68. data/lib/rox/core/register/registerer.rb +13 -12
  69. data/lib/rox/core/reporting/error_reporter.rb +14 -13
  70. data/lib/rox/core/repositories/custom_property_repository.rb +1 -1
  71. data/lib/rox/core/repositories/experiment_repository.rb +2 -4
  72. data/lib/rox/core/repositories/flag_repository.rb +8 -8
  73. data/lib/rox/core/repositories/roxx/experiments_extensions.rb +8 -8
  74. data/lib/rox/core/repositories/roxx/properties_extensions.rb +32 -7
  75. data/lib/rox/core/repositories/target_group_repository.rb +2 -4
  76. data/lib/rox/core/roxx/evaluation_result.rb +2 -0
  77. data/lib/rox/core/roxx/node.rb +1 -1
  78. data/lib/rox/core/roxx/parser.rb +46 -20
  79. data/lib/rox/core/roxx/regular_expression_extensions.rb +6 -3
  80. data/lib/rox/core/roxx/string_tokenizer.rb +3 -1
  81. data/lib/rox/core/roxx/symbols.rb +1 -1
  82. data/lib/rox/core/roxx/token_type.rb +1 -1
  83. data/lib/rox/core/roxx/tokenized_expression.rb +16 -12
  84. data/lib/rox/core/roxx/value_compare_extensions.rb +49 -29
  85. data/lib/rox/core/security/signature_verifier.rb +3 -3
  86. data/lib/rox/core/security/signature_verifier_mock.rb +12 -0
  87. data/lib/rox/core/utils/debouncer.rb +18 -0
  88. data/lib/rox/core/utils/type_utils.rb +1 -1
  89. data/lib/rox/server/client/sdk_settings.rb +1 -1
  90. data/lib/rox/server/client/server_properties.rb +1 -1
  91. data/lib/rox/server/flags/normalize_flag_type.rb +25 -0
  92. data/lib/rox/server/flags/rox_double.rb +8 -0
  93. data/lib/rox/server/flags/rox_flag.rb +1 -1
  94. data/lib/rox/server/flags/rox_int.rb +8 -0
  95. data/lib/rox/server/flags/rox_string.rb +8 -0
  96. data/lib/rox/server/flags/server_entities_provider.rb +14 -4
  97. data/lib/rox/server/logging/server_logger.rb +2 -2
  98. data/lib/rox/server/rox_options.rb +39 -8
  99. data/lib/rox/server/rox_server.rb +81 -60
  100. data/lib/rox/version.rb +1 -1
  101. data/rox.gemspec +13 -9
  102. metadata +95 -36
  103. data/README_DEVELOP.md +0 -19
  104. data/_archive/.document +0 -5
  105. data/_archive/.rspec +0 -1
  106. data/_archive/Gemfile +0 -15
  107. data/_archive/Gemfile.lock +0 -87
  108. data/_archive/README.md +0 -32
  109. data/_archive/README.rdoc +0 -19
  110. data/_archive/Rakefile +0 -50
  111. data/_archive/lib/expr_function_definition.rb +0 -52
  112. data/_archive/lib/function_definition.rb +0 -48
  113. data/_archive/lib/function_token.rb +0 -12
  114. data/_archive/lib/object_extends.rb +0 -12
  115. data/_archive/lib/ruby_interpreter.rb +0 -292
  116. data/_archive/lib/stack.rb +0 -48
  117. data/_archive/lib/string_extends.rb +0 -14
  118. data/_archive/spec/ruby_interpreter_spec.rb +0 -203
  119. data/_archive/spec/spec_helper.rb +0 -30
  120. data/_archive/spec/stack_spec.rb +0 -77
  121. data/lib/rox/server/flags/rox_variant.rb +0 -8
@@ -0,0 +1,30 @@
1
+ require 'rox/core/network/configuration_source'
2
+ require 'rox/core/network/configuration_fetch_result'
3
+ require 'rox/core/network/configuration_fetcher_base'
4
+
5
+ module Rox
6
+ module Core
7
+ class ConfigurationFetcherSelfManaged < ConfigurationFetcherBase
8
+ def fetch
9
+ source = ConfigurationSource::API
10
+ begin
11
+ fetch_result = fetch_from_api
12
+ if fetch_result.success?
13
+ return ConfigurationFetchResult.new(fetch_result.text, source)
14
+ else
15
+ write_fetch_error_to_log_and_invoke_fetch_handler(source, fetch_result)
16
+ end
17
+ rescue StandardError => e
18
+ write_fetch_exception_to_log_and_invoke_fetch_handler(source, e)
19
+ end
20
+
21
+ nil
22
+ end
23
+
24
+ def fetch_from_api
25
+ api_request = @request_configuration_builder.build_for_api
26
+ @request.send_post(api_request.url, api_request.query_params)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -6,4 +6,4 @@ module Rox
6
6
  ROXY = 'Roxy'.freeze
7
7
  end
8
8
  end
9
- end
9
+ end
@@ -28,7 +28,7 @@ module Rox
28
28
  request.body = JSON.dump(payload)
29
29
  end
30
30
 
31
- resp = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => uri.scheme == 'https') do |http|
31
+ resp = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
32
32
  http.request(request)
33
33
  end
34
34
 
@@ -39,8 +39,8 @@ module Rox
39
39
  resp_body = gz.read
40
40
  end
41
41
 
42
- Response.new(resp.code.to_i, resp_body)
42
+ Response.new(resp.code.to_i, resp_body, resp['Content-Type'])
43
43
  end
44
44
  end
45
45
  end
46
- end
46
+ end
@@ -5,25 +5,29 @@ require 'rox/core/consts/property_type'
5
5
  module Rox
6
6
  module Core
7
7
  class RequestConfigurationBuilder
8
- def initialize(sdk_settings, buid, device_properties, roxy_url)
8
+ def initialize(sdk_settings, buid, device_properties)
9
9
  @sdk_settings = sdk_settings
10
10
  @buid = buid
11
11
  @device_properties = device_properties
12
- @roxy_url = roxy_url
12
+ @rox_options = device_properties.rox_options
13
13
  end
14
14
 
15
15
  def build_for_roxy
16
- roxy_endpoint = URI.join(@roxy_url, Rox::Core::Environment.roxy_internal_path).to_s
16
+ roxy_endpoint = URI.join(@rox_options.roxy_url, Rox::Core::Environment.roxy_internal_path).to_s
17
17
  build_request_with_full_params(roxy_endpoint)
18
18
  end
19
19
 
20
20
  def build_for_cdn
21
- RequestData.new("#{Rox::Core::Environment.cdn_path}/#{@buid.value}",
22
- Rox::Core::PropertyType::DISTINCT_ID.name => @device_properties.distinct_id)
21
+ RequestData.new("#{Rox::Core::Environment.cdn_path}/#{relative_path}",
22
+ Rox::Core::PropertyType::DISTINCT_ID.name => @device_properties.distinct_id)
23
23
  end
24
24
 
25
25
  def build_for_api
26
- build_request_with_full_params(Rox::Core::Environment.api_path)
26
+ build_request_with_full_params("#{Rox::Core::Environment.api_path(@rox_options.self_managed_options&.server_url)}/#{relative_path}")
27
+ end
28
+
29
+ def relative_path
30
+ "#{@device_properties.rollout_key}/#{@buid.value}"
27
31
  end
28
32
 
29
33
  def build_request_with_full_params(url)
@@ -37,12 +41,11 @@ module Rox
37
41
  query_params[key] = value unless query_params.include?(key)
38
42
  end
39
43
 
40
- cdn_data = build_for_cdn
41
- query_params[Rox::Core::PropertyType::CACHE_MISS_URL.name] = cdn_data.url
44
+ query_params[Rox::Core::PropertyType::CACHE_MISS_RELATIVE_URL.name] = relative_path
42
45
  query_params['devModeSecret'] = @sdk_settings.dev_mode_secret
43
46
 
44
47
  RequestData.new(url, query_params)
45
48
  end
46
49
  end
47
50
  end
48
- end
51
+ end
@@ -2,4 +2,4 @@ module Rox
2
2
  module Core
3
3
  RequestData = Struct.new(:url, :query_params)
4
4
  end
5
- end
5
+ end
@@ -1,16 +1,32 @@
1
+ require 'json'
2
+ require 'rox/core/logging/logging'
3
+
1
4
  module Rox
2
5
  module Core
3
6
  class Response
4
- attr_accessor :status_code, :text
7
+ attr_accessor :status_code, :text, :content_type
5
8
 
6
- def initialize(status_code, text)
9
+ def initialize(status_code, text, content_type = 'application/octet-stream')
7
10
  @status_code = status_code
8
11
  @text = text
12
+ @content_type = content_type
13
+ end
14
+
15
+ def success?
16
+ status_code_success? && !missing_via_response_body?
9
17
  end
10
18
 
11
- def success_status_code?
19
+ def status_code_success?
12
20
  @status_code >= 200 && @status_code < 300
13
21
  end
22
+
23
+ def missing_via_response_body?
24
+ @status_code == 200 && @content_type == 'application/json' &&
25
+ [404, '404'].include?(JSON.parse(text)['result'])
26
+ rescue JSON::ParserError
27
+ Logging.logger.error("Failed to parse JSON response: #{text}")
28
+ false
29
+ end
14
30
  end
15
31
  end
16
- end
32
+ end
@@ -0,0 +1,146 @@
1
+ require 'digest'
2
+ require 'json'
3
+
4
+ require 'rox/core/consts/environment'
5
+ require 'rox/core/consts/property_type'
6
+ require 'rox/core/logging/logging'
7
+ require 'rox/core/network/request'
8
+ require 'rox/core/network/request_data'
9
+ require 'rox/core/network/response'
10
+ require 'rox/core/utils/debouncer'
11
+
12
+ module Rox
13
+ module Core
14
+ class StateSender
15
+ def initialize(sdk_settings, device_properties, flag_repository, custom_property_repository)
16
+ @sdk_settings = sdk_settings
17
+ @device_properties = device_properties
18
+ @flag_repository = flag_repository
19
+ @custom_property_repository = custom_property_repository
20
+ @request = Request.new
21
+ @debouncer = Debouncer.new(1, proc { send })
22
+ end
23
+
24
+ def delayed_send
25
+ @debouncer.call
26
+ end
27
+
28
+ def send
29
+ rollout_key = @device_properties.rollout_key
30
+ serialized_feature_flags = StateSender.seralize_flag_repository(@flag_repository)
31
+ serialized_custom_properties = StateSender.serialize_custom_properties_repository(@custom_property_repository)
32
+
33
+ state_payload = StateSender.state_payload(serialized_feature_flags, serialized_custom_properties,
34
+ @device_properties, @sdk_settings.dev_mode_secret)
35
+ md5_signature = StateSender.md5_signature(serialized_feature_flags, serialized_custom_properties,
36
+ @device_properties, @sdk_settings.dev_mode_secret)
37
+
38
+ unless @device_properties.rox_options.self_managed?
39
+ response = get_state_from_CDN(rollout_key, md5_signature)
40
+ if response.success?
41
+ Rox::Core::Logging.logger.debug('Successfully fetched state from CDN')
42
+ return
43
+ else
44
+ Rox::Core::Logging.logger.debug('Failed to fetch state from CDN. Sending state to API...')
45
+ end
46
+ end
47
+
48
+ response = send_state_to_API(rollout_key, md5_signature, state_payload)
49
+ message = if response.success?
50
+ 'Successfully sent state to API.'
51
+ else
52
+ 'Failed to send state to API.'
53
+ end
54
+ Rox::Core::Logging.logger.debug(message)
55
+ end
56
+
57
+ def dump_state
58
+ serialized_feature_flags = StateSender.seralize_flag_repository_with_values(@flag_repository)
59
+ serialized_custom_properties = StateSender.serialize_custom_properties_repository_with_values(@custom_property_repository)
60
+ StateSender.state_payload(serialized_feature_flags, serialized_custom_properties, @device_properties,
61
+ @sdk_settings.dev_mode_secret)
62
+ end
63
+
64
+ def get_state_from_CDN(rollout_key, md5_signature)
65
+ url_for_state_cdn =
66
+ RequestData.new("#{Rox::Core::Environment.state_cdn_path}/#{rollout_key}/#{md5_signature}", {})
67
+ @request.send_get(url_for_state_cdn)
68
+ end
69
+
70
+ def send_state_to_API(rollout_key, md5_signature, state_payload)
71
+ @request.send_post(
72
+ "#{Rox::Core::Environment.state_api_path(@device_properties.rox_options.self_managed_options&.server_url)}/#{rollout_key}/#{md5_signature}", state_payload
73
+ )
74
+ end
75
+
76
+ def self.md5_signature(serialized_feature_flags, serialized_custom_properties, device_properties, dev_mode_secret)
77
+ values = state_payload(serialized_feature_flags, serialized_custom_properties, device_properties,
78
+ dev_mode_secret).values
79
+
80
+ hash = Digest::MD5.hexdigest(values.join('|'))
81
+ hash.upcase
82
+ end
83
+
84
+ def self.state_payload(seralized_flag_repository, serialized_custom_property_repository, device_properties, dev_mode_secret)
85
+ values = {}
86
+ values[PropertyType::APP_KEY.name] = device_properties.all_properties[PropertyType::APP_KEY.name]
87
+ values[PropertyType::PLATFORM.name] = device_properties.all_properties[PropertyType::PLATFORM.name]
88
+ values.merge!(device_properties.all_properties)
89
+ values.merge!({ feature_flags: seralized_flag_repository })
90
+ values.merge!({ custom_properties: serialized_custom_property_repository })
91
+ values['devModeSecret'] = dev_mode_secret
92
+ values
93
+ end
94
+
95
+ def self.seralize_flag_repository(flag_repository)
96
+ flags = []
97
+ flag_repository.all_flags.sort_by(&:name).each do |f|
98
+ flags << {
99
+ name: f.name,
100
+ defaultValue: f.default_value,
101
+ options: f.options
102
+ }
103
+ end
104
+ flags
105
+ end
106
+
107
+ def self.seralize_flag_repository_with_values(flag_repository)
108
+ flags = []
109
+ flag_repository.all_flags.sort_by(&:name).each do |f|
110
+ flags << {
111
+ name: f.name,
112
+ enabled: f.enabled?,
113
+ defaultValue: f.default_value,
114
+ options: f.options
115
+ }
116
+ end
117
+ flags
118
+ end
119
+
120
+ def self.serialize_custom_properties_repository(custom_property_repository)
121
+ properties = []
122
+ custom_property_repository.all_custom_properties.sort_by(&:name).each do |p|
123
+ properties << {
124
+ name: p.name,
125
+ type: p.type.type,
126
+ externalType: p.type.external_type
127
+ }
128
+ end
129
+ properties
130
+ end
131
+
132
+ def self.serialize_custom_properties_repository_with_values(custom_property_repository)
133
+ properties = []
134
+ custom_property_repository.all_custom_properties.sort_by(&:name).each do |p|
135
+ properties << {
136
+ name: p.name,
137
+ value: p.value(nil),
138
+ type: p.type.type,
139
+ externalType: p.type.external_type
140
+ }
141
+ end
142
+ properties
143
+ end
144
+ end
145
+ end
146
+ end
@@ -1,4 +1,4 @@
1
- require "em-eventsource"
1
+ require 'em-eventsource'
2
2
 
3
3
  module Rox
4
4
  module Core
@@ -15,7 +15,7 @@ module Rox
15
15
  end
16
16
 
17
17
  def start
18
- sse_url = @listen_url.chomp('/') + '/' + @app_key
18
+ sse_url = "#{@listen_url.chomp('/')}/#{@app_key}"
19
19
  @thread = Thread.new do
20
20
  EM.run do
21
21
  source = EventMachine::EventSource.new(sse_url)
@@ -37,9 +37,9 @@ module Rox
37
37
  end
38
38
 
39
39
  def stop
40
- @thread.terminate unless @thread.nil?
40
+ @thread&.terminate
41
41
  @thread = nil
42
42
  end
43
43
  end
44
44
  end
45
- end
45
+ end
@@ -15,4 +15,4 @@ module Rox
15
15
  end
16
16
  end
17
17
  end
18
- end
18
+ end
@@ -15,4 +15,4 @@ module Rox
15
15
  SEMVER = CustomPropertyType.new('semver', 'Semver')
16
16
  end
17
17
  end
18
- end
18
+ end
@@ -4,8 +4,8 @@ module Rox
4
4
  module Core
5
5
  class DeviceProperty < CustomProperty
6
6
  def initialize(name, type, value = nil)
7
- super('rox.' + name, type, value)
7
+ super("rox.#{name}", type, value)
8
8
  end
9
9
  end
10
10
  end
11
- end
11
+ end
@@ -0,0 +1,132 @@
1
+ require 'securerandom'
2
+ require 'rox/server/rox_options'
3
+ require 'rox/server/client/sdk_settings'
4
+ require 'rox/server/client/server_properties'
5
+ require 'rox/core/properties/device_property'
6
+ require 'rox/core/properties/custom_property'
7
+ require 'rox/core/properties/custom_property_type'
8
+ require 'rox/core/consts/property_type'
9
+
10
+ module Rox
11
+ module Core
12
+ # Consolidates creation of all the internal properties
13
+ class PropertyFactory
14
+ def initialize(server_properties)
15
+ @server_properties = server_properties
16
+ end
17
+
18
+ def platform
19
+ property = Rox::Core::PropertyType::PLATFORM
20
+ type = Rox::Core::CustomPropertyType::STRING
21
+
22
+ Rox::Core::DeviceProperty.new(
23
+ property.name,
24
+ type,
25
+ @server_properties.get(property)
26
+ )
27
+ end
28
+
29
+ def app_release
30
+ property = Rox::Core::PropertyType::APP_RELEASE
31
+ type = Rox::Core::CustomPropertyType::SEMVER
32
+
33
+ Rox::Core::DeviceProperty.new(
34
+ property.name,
35
+ type,
36
+ @server_properties.get(property)
37
+ )
38
+ end
39
+
40
+ def distinct_id
41
+ property = Rox::Core::PropertyType::DISTINCT_ID
42
+ type = Rox::Core::CustomPropertyType::STRING
43
+
44
+ Rox::Core::DeviceProperty.new(
45
+ property.name,
46
+ type
47
+ ) do |_|
48
+ SecureRandom.uuid
49
+ end
50
+ end
51
+
52
+ def internal_real_platform
53
+ property = Rox::Core::PropertyType::PLATFORM
54
+ type = Rox::Core::CustomPropertyType::STRING
55
+
56
+ Rox::Core::DeviceProperty.new(
57
+ 'internal.realPlatform',
58
+ type,
59
+ @server_properties.get(property)
60
+ )
61
+ end
62
+
63
+ def internal_custom_platform
64
+ property = Rox::Core::PropertyType::PLATFORM
65
+ type = Rox::Core::CustomPropertyType::STRING
66
+
67
+ Rox::Core::DeviceProperty.new(
68
+ 'internal.customPlatform',
69
+ type,
70
+ @server_properties.get(property)
71
+ )
72
+ end
73
+
74
+ def internal_app_key
75
+ type = Rox::Core::CustomPropertyType::STRING
76
+
77
+ Rox::Core::DeviceProperty.new(
78
+ 'internal.appKey',
79
+ type,
80
+ @server_properties.rollout_key
81
+ )
82
+ end
83
+
84
+ def internal_distinct_id
85
+ type = Rox::Core::CustomPropertyType::STRING
86
+
87
+ Rox::Core::DeviceProperty.new(
88
+ "internal.#{Rox::Core::PropertyType::DISTINCT_ID.name}",
89
+ type
90
+ ) do
91
+ SecureRandom.uuid
92
+ end
93
+ end
94
+
95
+ def internal_lib_version
96
+ type = Rox::Core::CustomPropertyType::SEMVER
97
+
98
+ Rox::Core::DeviceProperty.new(
99
+ 'internal.lib_version',
100
+ type,
101
+ @server_properties.lib_version
102
+ )
103
+ end
104
+
105
+ def internal_api_version
106
+ property = Rox::Core::PropertyType::API_VERSION
107
+ type = Rox::Core::CustomPropertyType::SEMVER
108
+
109
+ Rox::Core::DeviceProperty.new(
110
+ 'internal.api_version',
111
+ type,
112
+ property
113
+ )
114
+ end
115
+
116
+ # rubocop:disable Metrics/MethodLength
117
+ def all_properties
118
+ [
119
+ platform,
120
+ app_release,
121
+ distinct_id,
122
+ internal_real_platform,
123
+ internal_custom_platform,
124
+ internal_app_key,
125
+ internal_distinct_id,
126
+ internal_lib_version,
127
+ internal_api_version
128
+ ]
129
+ end
130
+ end
131
+ end
132
+ end