prefab-cloud-ruby 1.7.1 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c3b95e2969c65849875591221843811b015a60ac51b8281b090a4e0a81bdc813
4
- data.tar.gz: c7dcf60b7d6b8a49d973ce1208ba6c56e31bb140aaffda2cfc1ee0fad453fc06
3
+ metadata.gz: 9cc77b24b0cabb61c5ffb820116e8cf1a5122ceb4fae6e0d56245be4ab165eb9
4
+ data.tar.gz: 11e541dfe23555733292de53b1d3193291b81dd412cea70e6126b0c042f52f12
5
5
  SHA512:
6
- metadata.gz: 6a15672e8ab7597ad858aa32424850b5beab72a6066c0111253c6ca43d2407de0ec8c9ccebf654d8f1a7ff730675cac966050b2143293b475f728adc672bdc46
7
- data.tar.gz: c14415715bfdf5e61d1075e2cd9f29a91e01f320d4305cd4328397ad5d88792a49ec5a215e791b343f687cc23f997aa24c106887a66508be6f3d980badfb4deb
6
+ metadata.gz: 795e04559f5dab867e30ba1ce58a622c4c651b7214a1dcfadde0d8fcac1825c88699b019fc36a1a88cd56a94dc89fb9564d773262b4a0e4d07247c5bc60a1cd4
7
+ data.tar.gz: 2e4718e509231db718a65e18d766a7d481b72e344c9d73d766a17fbe91619a30694799b622a0fdbc419f440c93a449abb1fdc00dfb58ea75c0c5387f190df23e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.8.0 - 2024-08-22
4
+
5
+ - Load config from belt and failover to suspenders (#195)
6
+
7
+ ## 1.7.2 - 2024-06-24
8
+
9
+ - Support JSON config values (#194)
10
+
3
11
  ## 1.7.1 - 2024-04-11
4
12
 
5
13
  - Ergonomics (#191)
data/Gemfile.lock CHANGED
@@ -101,7 +101,7 @@ GEM
101
101
  rake (~> 13.0)
102
102
  macaddr (1.7.2)
103
103
  systemu (~> 2.6.5)
104
- mini_portile2 (2.8.5)
104
+ mini_portile2 (2.8.7)
105
105
  minitest (5.22.3)
106
106
  minitest-focus (1.4.0)
107
107
  minitest (>= 4, < 6)
@@ -114,7 +114,7 @@ GEM
114
114
  multi_xml (0.6.0)
115
115
  multipart-post (2.4.0)
116
116
  mutex_m (0.2.0)
117
- nokogiri (1.16.3)
117
+ nokogiri (1.16.7)
118
118
  mini_portile2 (~> 2.8.2)
119
119
  racc (~> 1.4)
120
120
  oauth2 (1.4.11)
@@ -126,7 +126,7 @@ GEM
126
126
  psych (5.1.2)
127
127
  stringio
128
128
  public_suffix (5.0.4)
129
- racc (1.7.3)
129
+ racc (1.8.1)
130
130
  rack (3.0.10)
131
131
  rake (13.1.0)
132
132
  rchardet (1.8.0)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.7.1
1
+ 1.8.0
data/lib/prefab/client.rb CHANGED
@@ -8,7 +8,7 @@ module Prefab
8
8
  MAX_SLEEP_SEC = 10
9
9
  BASE_SLEEP_SEC = 0.5
10
10
 
11
- attr_reader :namespace, :interceptor, :api_key, :prefab_api_url, :options, :instance_hash
11
+ attr_reader :namespace, :interceptor, :api_key, :options, :instance_hash
12
12
 
13
13
  def initialize(options = Prefab::Options.new)
14
14
  @options = options.is_a?(Prefab::Options) ? options : Prefab::Options.new(options)
@@ -23,9 +23,6 @@ module Prefab
23
23
  else
24
24
  @api_key = @options.api_key
25
25
  raise Prefab::Errors::InvalidApiKeyError, @api_key if @api_key.nil? || @api_key.empty? || api_key.count('-') < 1
26
-
27
- @prefab_api_url = @options.prefab_api_url
28
- LOG.debug "Prefab Connecting to: #{@prefab_api_url}"
29
26
  end
30
27
 
31
28
  context.clear
@@ -48,6 +45,10 @@ module Prefab
48
45
  @config_client ||= Prefab::ConfigClient.new(self, timeout)
49
46
  end
50
47
 
48
+ def stop
49
+ @config_client.stop
50
+ end
51
+
51
52
  def feature_flag_client
52
53
  @feature_flag_client ||= Prefab::FeatureFlagClient.new(self)
53
54
  end
@@ -111,7 +112,7 @@ module Prefab
111
112
  end
112
113
 
113
114
  def post(path, body)
114
- Prefab::HttpConnection.new(@options.prefab_api_url, @api_key).post(path, body)
115
+ Prefab::HttpConnection.new(@options.telemetry_destination, @api_key).post(path, body)
115
116
  end
116
117
 
117
118
  def inspect
@@ -3,19 +3,15 @@
3
3
  module Prefab
4
4
  class ConfigClient
5
5
  LOG = Prefab::InternalLogger.new(self)
6
- RECONNECT_WAIT = 5
7
6
  DEFAULT_CHECKPOINT_FREQ_SEC = 60
8
- SSE_READ_TIMEOUT = 300
9
7
  STALE_CACHE_WARN_HOURS = 5
10
- AUTH_USER = 'authuser'
8
+
11
9
  def initialize(base_client, timeout)
12
10
  @base_client = base_client
13
11
  @options = base_client.options
14
12
  LOG.debug 'Initialize ConfigClient'
15
13
  @timeout = timeout
16
14
 
17
- @stream_lock = Concurrent::ReadWriteLock.new
18
-
19
15
  @checkpoint_freq_secs = DEFAULT_CHECKPOINT_FREQ_SEC
20
16
 
21
17
  @config_loader = Prefab::ConfigLoader.new(@base_client)
@@ -34,9 +30,27 @@ module Prefab
34
30
  end
35
31
  end
36
32
 
33
+ def stop
34
+ @sse_config_client&.close
35
+ end
36
+
37
37
  def start_streaming
38
- @stream_lock.with_write_lock do
39
- start_sse_streaming_connection_thread(@config_loader.highwater_mark) if @streaming_thread.nil?
38
+ Thread.new do
39
+ # wait for the config loader to have a highwater mark before we connect the SSE
40
+ loop do
41
+ break if @config_loader.highwater_mark > 0
42
+
43
+ sleep 0.1
44
+ end
45
+
46
+ stream_lock = Concurrent::ReadWriteLock.new
47
+ @sse_config_client = Prefab::SSEConfigClient.new(@options, @config_loader)
48
+
49
+ @sse_config_client.start do |configs|
50
+ stream_lock.with_write_lock do
51
+ load_configs(configs, :sse)
52
+ end
53
+ end
40
54
  end
41
55
  end
42
56
 
@@ -104,29 +118,24 @@ module Prefab
104
118
  end
105
119
 
106
120
  def load_checkpoint
107
- success = load_checkpoint_api_cdn
108
-
109
- return if success
110
-
111
- success = load_checkpoint_api
112
-
121
+ success = load_source_checkpoint
113
122
  return if success
114
123
 
115
124
  success = load_cache
116
-
117
125
  return if success
118
126
 
119
127
  LOG.warn 'No success loading checkpoints'
120
128
  end
121
129
 
122
- def load_checkpoint_api_cdn
123
- conn = Prefab::HttpConnection.new("#{@options.url_for_api_cdn}/api/v1/configs/0", @base_client.api_key)
124
- load_url(conn, :remote_cdn_api)
125
- end
130
+ def load_source_checkpoint
131
+ @options.config_sources.each do |source|
132
+ conn = Prefab::HttpConnection.new("#{source}/api/v1/configs/0", @base_client.api_key)
133
+ result = load_url(conn, :remote_api)
126
134
 
127
- def load_checkpoint_api
128
- conn = Prefab::HttpConnection.new("#{@options.prefab_api_url}/api/v1/configs/0", @base_client.api_key)
129
- load_url(conn, :remote_api)
135
+ return true if result
136
+ end
137
+
138
+ return false
130
139
  end
131
140
 
132
141
  def load_url(conn, source)
@@ -263,26 +272,5 @@ module Prefab
263
272
  LOG.info presenter.to_s
264
273
  LOG.debug to_s
265
274
  end
266
-
267
- def start_sse_streaming_connection_thread(start_at_id)
268
- auth = "#{AUTH_USER}:#{@base_client.api_key}"
269
- auth_string = Base64.strict_encode64(auth)
270
- headers = {
271
- 'x-prefab-start-at-id' => start_at_id,
272
- 'Authorization' => "Basic #{auth_string}",
273
- 'X-PrefabCloud-Client-Version' => "prefab-cloud-ruby-#{Prefab::VERSION}"
274
- }
275
- url = "#{@base_client.prefab_api_url}/api/v1/sse/config"
276
- LOG.debug "SSE Streaming Connect to #{url} start_at #{start_at_id}"
277
- @streaming_thread = SSE::Client.new(url,
278
- headers: headers,
279
- read_timeout: SSE_READ_TIMEOUT,
280
- logger: Prefab::InternalLogger.new(SSE::Client)) do |client|
281
- client.on_event do |event|
282
- configs = PrefabProto::Configs.decode(Base64.decode64(event.data))
283
- load_configs(configs, :sse)
284
- end
285
- end
286
- end
287
275
  end
288
276
  end
@@ -38,6 +38,8 @@ module Prefab
38
38
  @config_value.string_list.values
39
39
  when :duration
40
40
  Prefab::Duration.new(@config_value.duration.definition)
41
+ when :json
42
+ JSON.parse(@config_value.json.json)
41
43
  else
42
44
  LOG.error "Unknown type: #{@config_value.type}"
43
45
  raise "Unknown type: #{@config_value.type}"
@@ -96,7 +96,6 @@ module Prefab
96
96
  @contexts = {}
97
97
  @flattened = {}
98
98
  @seen_at = Time.now.utc.to_i
99
- warned = false
100
99
 
101
100
  if hash.is_a?(Hash)
102
101
  hash.map do |name, values|
@@ -46,16 +46,22 @@ module Prefab
46
46
  pool.post do
47
47
  LOG.debug "Uploading context shapes for #{to_ship.values.size}"
48
48
 
49
- shapes = PrefabProto::ContextShapes.new(
50
- shapes: to_ship.map do |name, shape|
51
- PrefabProto::ContextShape.new(
52
- name: name,
53
- field_types: shape
54
- )
55
- end
49
+ events = PrefabProto::TelemetryEvents.new(
50
+ instance_hash: instance_hash,
51
+ events: [
52
+ PrefabProto::TelemetryEvent.new(context_shapes:
53
+ PrefabProto::ContextShapes.new(
54
+ shapes: to_ship.map do |name, shape|
55
+ PrefabProto::ContextShape.new(
56
+ name: name,
57
+ field_types: shape
58
+ )
59
+ end
60
+ ))
61
+ ]
56
62
  )
57
63
 
58
- result = post('/api/v1/context-shapes', shapes)
64
+ result = post('/api/v1/telemetry', events)
59
65
 
60
66
  LOG.debug "Uploaded #{to_ship.values.size} shapes: #{result.status}"
61
67
  end
@@ -45,11 +45,13 @@ module Prefab
45
45
  end
46
46
 
47
47
  def PROP_IS_ONE_OF(criterion, properties)
48
- matches?(criterion, value_from_properties(criterion, properties), properties)
48
+ Array(value_from_properties(criterion, properties)).any? do |prop|
49
+ matches?(criterion, prop, properties)
50
+ end
49
51
  end
50
52
 
51
53
  def PROP_IS_NOT_ONE_OF(criterion, properties)
52
- !matches?(criterion, value_from_properties(criterion, properties), properties)
54
+ !PROP_IS_ONE_OF(criterion, properties)
53
55
  end
54
56
 
55
57
  def PROP_ENDS_WITH_ONE_OF(criterion, properties)
@@ -57,7 +59,7 @@ module Prefab
57
59
  end
58
60
 
59
61
  def PROP_DOES_NOT_END_WITH_ONE_OF(criterion, properties)
60
- !prop_ends_with_one_of?(criterion, value_from_properties(criterion, properties))
62
+ !PROP_ENDS_WITH_ONE_OF(criterion, properties)
61
63
  end
62
64
 
63
65
  def HIERARCHICAL_MATCH(criterion, properties)
@@ -51,15 +51,16 @@ module Prefab
51
51
  aggregate[path]['logger_name'] = path
52
52
  end
53
53
 
54
- loggers = PrefabProto::Loggers.new(
55
- loggers: aggregate.values,
56
- start_at: start_at_was,
57
- end_at: Prefab::TimeHelpers.now_in_ms,
58
- instance_hash: @client.instance_hash,
59
- namespace: @client.namespace
54
+ loggers = PrefabProto::LoggersTelemetryEvent.new(loggers: aggregate.values,
55
+ start_at: start_at_was,
56
+ end_at: Prefab::TimeHelpers.now_in_ms)
57
+
58
+ events = PrefabProto::TelemetryEvents.new(
59
+ instance_hash: instance_hash,
60
+ events: [PrefabProto::TelemetryEvent.new(loggers: loggers)]
60
61
  )
61
62
 
62
- result = post('/api/v1/known-loggers', loggers)
63
+ result = post('/api/v1/telemetry', events)
63
64
 
64
65
  LOG.debug "Uploaded #{to_ship.size} paths: #{result.status}"
65
66
  end
@@ -5,7 +5,10 @@ module Prefab
5
5
  class Options
6
6
  attr_reader :api_key
7
7
  attr_reader :namespace
8
- attr_reader :prefab_api_url
8
+ attr_reader :sources
9
+ attr_reader :sse_sources
10
+ attr_reader :telemetry_destination
11
+ attr_reader :config_sources
9
12
  attr_reader :on_no_default
10
13
  attr_reader :initialization_timeout_sec
11
14
  attr_reader :on_init_failure
@@ -38,10 +41,16 @@ module Prefab
38
41
  DEFAULT_MAX_EXAMPLE_CONTEXTS = 100_000
39
42
  DEFAULT_MAX_EVAL_SUMMARIES = 100_000
40
43
 
44
+ DEFAULT_SOURCES = [
45
+ "https://belt.prefab.cloud",
46
+ "https://suspenders.prefab.cloud",
47
+ ].freeze
48
+
41
49
  private def init(
50
+ sources: nil,
42
51
  api_key: ENV['PREFAB_API_KEY'],
43
52
  namespace: '',
44
- prefab_api_url: ENV['PREFAB_API_URL'] || 'https://api.prefab.cloud',
53
+ prefab_api_url: nil,
45
54
  on_no_default: ON_NO_DEFAULT::RAISE, # options :raise, :warn_and_return_nil,
46
55
  initialization_timeout_sec: 10, # how long to wait before on_init_failure
47
56
  on_init_failure: ON_INITIALIZATION_FAILURE::RAISE,
@@ -63,7 +72,6 @@ module Prefab
63
72
  )
64
73
  @api_key = api_key
65
74
  @namespace = namespace
66
- @prefab_api_url = remove_trailing_slash(prefab_api_url)
67
75
  @on_no_default = on_no_default
68
76
  @initialization_timeout_sec = initialization_timeout_sec
69
77
  @on_init_failure = on_init_failure
@@ -88,6 +96,25 @@ module Prefab
88
96
  @collect_example_contexts = false
89
97
  @collect_max_example_contexts = 0
90
98
 
99
+ if ENV['PREFAB_API_URL_OVERRIDE'] && ENV['PREFAB_API_URL_OVERRIDE'].length > 0
100
+ sources = ENV['PREFAB_API_URL_OVERRIDE']
101
+ end
102
+
103
+ @sources = Array(sources || DEFAULT_SOURCES).map {|source| remove_trailing_slash(source) }
104
+
105
+ @sse_sources = @sources
106
+ @config_sources = @sources
107
+
108
+ @telemetry_destination = @sources.select do |source|
109
+ source.start_with?('https://') && (source.include?("belt") || source.include?("suspenders"))
110
+ end.map do |source|
111
+ source.sub(/(belt|suspenders)\./, 'telemetry.')
112
+ end[0]
113
+
114
+ if prefab_api_url
115
+ warn '[DEPRECATION] prefab_api_url is deprecated. Please provide `sources` if you need to override the default sources'
116
+ end
117
+
91
118
  case context_upload_mode
92
119
  when :none
93
120
  # do nothing
@@ -140,11 +167,6 @@ module Prefab
140
167
  @collect_max_evaluation_summaries
141
168
  end
142
169
 
143
- # https://api.prefab.cloud -> https://api-prefab-cloud.global.ssl.fastly.net
144
- def url_for_api_cdn
145
- ENV['PREFAB_CDN_URL'] || "#{@prefab_api_url.gsub(/\./, '-')}.global.ssl.fastly.net"
146
- end
147
-
148
170
  def api_key_id
149
171
  @api_key&.split("-")&.first
150
172
  end
@@ -32,6 +32,10 @@ module Prefab
32
32
  @client.post(url, data)
33
33
  end
34
34
 
35
+ def instance_hash
36
+ @client.instance_hash
37
+ end
38
+
35
39
  def start_periodic_sync(sync_interval)
36
40
  @start_at = Prefab::TimeHelpers.now_in_ms
37
41
 
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Prefab
4
+ class SSEConfigClient
5
+ SSE_READ_TIMEOUT = 300
6
+ SECONDS_BETWEEN_RECONNECT = 5
7
+ AUTH_USER = 'authuser'
8
+ LOG = Prefab::InternalLogger.new(self)
9
+
10
+ def initialize(options, config_loader)
11
+ @options = options
12
+ @config_loader = config_loader
13
+ @connected = false
14
+ end
15
+
16
+ def close
17
+ @retry_thread&.kill
18
+ @client&.close
19
+ end
20
+
21
+ def start(&load_configs)
22
+ if @options.sse_sources.empty?
23
+ LOG.debug 'No SSE sources configured'
24
+ return
25
+ end
26
+
27
+ @client = connect(&load_configs)
28
+
29
+ closed_count = 0
30
+
31
+ @retry_thread = Thread.new do
32
+ loop do
33
+ sleep 1
34
+
35
+ if @client.closed?
36
+ closed_count += 1
37
+
38
+ if closed_count > SECONDS_BETWEEN_RECONNECT
39
+ closed_count = 0
40
+ connect(&load_configs)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ def connect(&load_configs)
48
+ url = "#{source}/api/v1/sse/config"
49
+ LOG.debug "SSE Streaming Connect to #{url} start_at #{@config_loader.highwater_mark}"
50
+
51
+ SSE::Client.new(url,
52
+ headers: headers,
53
+ read_timeout: SSE_READ_TIMEOUT,
54
+ logger: Prefab::InternalLogger.new(SSE::Client)) do |client|
55
+ client.on_event do |event|
56
+ configs = PrefabProto::Configs.decode(Base64.decode64(event.data))
57
+ load_configs.call(configs, :sse)
58
+ end
59
+
60
+ client.on_error do |error|
61
+ LOG.error "SSE Streaming Error: #{error} for url #{url}"
62
+
63
+ if error.is_a?(HTTP::ConnectionError)
64
+ client.close
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ def headers
71
+ auth = "#{AUTH_USER}:#{@options.api_key}"
72
+ auth_string = Base64.strict_encode64(auth)
73
+ return {
74
+ 'x-prefab-start-at-id' => @config_loader.highwater_mark,
75
+ 'Authorization' => "Basic #{auth_string}",
76
+ 'Accept' => 'text/event-stream',
77
+ 'X-PrefabCloud-Client-Version' => "prefab-cloud-ruby-#{Prefab::VERSION}"
78
+ }
79
+ end
80
+
81
+ def source
82
+ @source_index = @source_index.nil? ? 0 : @source_index + 1
83
+
84
+ if @source_index >= @options.sse_sources.size
85
+ @source_index = 0
86
+ end
87
+
88
+ return @options.sse_sources[@source_index]
89
+ end
90
+ end
91
+ end
@@ -46,6 +46,7 @@ require 'prefab/context'
46
46
  require 'prefab/logger_client'
47
47
  require 'active_support/deprecation'
48
48
  require 'active_support'
49
+ require 'prefab/sse_config_client'
49
50
  require 'prefab/client'
50
51
  require 'prefab/config_client_presenter'
51
52
  require 'prefab/config_client'
data/lib/prefab_pb.rb CHANGED
@@ -5,35 +5,15 @@
5
5
  require 'google/protobuf'
6
6
 
7
7
 
8
- descriptor_data = "\n\x0cprefab.proto\x12\x06prefab\"W\n\x14\x43onfigServicePointer\x12\x12\n\nproject_id\x18\x01 \x01(\x03\x12\x13\n\x0bstart_at_id\x18\x02 \x01(\x03\x12\x16\n\x0eproject_env_id\x18\x03 \x01(\x03\"\xf1\x03\n\x0b\x43onfigValue\x12\r\n\x03int\x18\x01 \x01(\x03H\x00\x12\x10\n\x06string\x18\x02 \x01(\tH\x00\x12\x0f\n\x05\x62ytes\x18\x03 \x01(\x0cH\x00\x12\x10\n\x06\x64ouble\x18\x04 \x01(\x01H\x00\x12\x0e\n\x04\x62ool\x18\x05 \x01(\x08H\x00\x12\x31\n\x0fweighted_values\x18\x06 \x01(\x0b\x32\x16.prefab.WeightedValuesH\x00\x12\x33\n\x10limit_definition\x18\x07 \x01(\x0b\x32\x17.prefab.LimitDefinitionH\x00\x12%\n\tlog_level\x18\t \x01(\x0e\x32\x10.prefab.LogLevelH\x00\x12)\n\x0bstring_list\x18\n \x01(\x0b\x32\x12.prefab.StringListH\x00\x12%\n\tint_range\x18\x0b \x01(\x0b\x32\x10.prefab.IntRangeH\x00\x12$\n\x08provided\x18\x0c \x01(\x0b\x32\x10.prefab.ProvidedH\x00\x12\'\n\x08\x64uration\x18\x0f \x01(\x0b\x32\x13.prefab.IsoDurationH\x00\x12\x19\n\x0c\x63onfidential\x18\r \x01(\x08H\x01\x88\x01\x01\x12\x19\n\x0c\x64\x65\x63rypt_with\x18\x0e \x01(\tH\x02\x88\x01\x01\x42\x06\n\x04typeB\x0f\n\r_confidentialB\x0f\n\r_decrypt_with\"!\n\x0bIsoDuration\x12\x12\n\ndefinition\x18\x01 \x01(\t\"b\n\x08Provided\x12+\n\x06source\x18\x01 \x01(\x0e\x32\x16.prefab.ProvidedSourceH\x00\x88\x01\x01\x12\x13\n\x06lookup\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\t\n\x07_sourceB\t\n\x07_lookup\"B\n\x08IntRange\x12\x12\n\x05start\x18\x01 \x01(\x03H\x00\x88\x01\x01\x12\x10\n\x03\x65nd\x18\x02 \x01(\x03H\x01\x88\x01\x01\x42\x08\n\x06_startB\x06\n\x04_end\"\x1c\n\nStringList\x12\x0e\n\x06values\x18\x01 \x03(\t\"C\n\rWeightedValue\x12\x0e\n\x06weight\x18\x01 \x01(\x05\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.prefab.ConfigValue\"~\n\x0eWeightedValues\x12.\n\x0fweighted_values\x18\x01 \x03(\x0b\x32\x15.prefab.WeightedValue\x12\"\n\x15hash_by_property_name\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x18\n\x16_hash_by_property_name\"X\n\x0e\x41piKeyMetadata\x12\x13\n\x06key_id\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x07user_id\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\t\n\x07_key_idB\n\n\x08_user_idJ\x04\x08\x02\x10\x03\"\xa0\x02\n\x07\x43onfigs\x12\x1f\n\x07\x63onfigs\x18\x01 \x03(\x0b\x32\x0e.prefab.Config\x12<\n\x16\x63onfig_service_pointer\x18\x02 \x01(\x0b\x32\x1c.prefab.ConfigServicePointer\x12\x34\n\x0f\x61pikey_metadata\x18\x03 \x01(\x0b\x32\x16.prefab.ApiKeyMetadataH\x00\x88\x01\x01\x12\x30\n\x0f\x64\x65\x66\x61ult_context\x18\x04 \x01(\x0b\x32\x12.prefab.ContextSetH\x01\x88\x01\x01\x12\x17\n\nkeep_alive\x18\x05 \x01(\x08H\x02\x88\x01\x01\x42\x12\n\x10_apikey_metadataB\x12\n\x10_default_contextB\r\n\x0b_keep_alive\"\xf2\x03\n\x06\x43onfig\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x12\n\nproject_id\x18\x02 \x01(\x03\x12\x0b\n\x03key\x18\x03 \x01(\t\x12%\n\nchanged_by\x18\x04 \x01(\x0b\x32\x11.prefab.ChangedBy\x12\x1f\n\x04rows\x18\x05 \x03(\x0b\x32\x11.prefab.ConfigRow\x12-\n\x10\x61llowable_values\x18\x06 \x03(\x0b\x32\x13.prefab.ConfigValue\x12\'\n\x0b\x63onfig_type\x18\x07 \x01(\x0e\x32\x12.prefab.ConfigType\x12\x15\n\x08\x64raft_id\x18\x08 \x01(\x03H\x00\x88\x01\x01\x12,\n\nvalue_type\x18\t \x01(\x0e\x32\x18.prefab.Config.ValueType\x12\x1a\n\x12send_to_client_sdk\x18\n \x01(\x08\"\xac\x01\n\tValueType\x12\x16\n\x12NOT_SET_VALUE_TYPE\x10\x00\x12\x07\n\x03INT\x10\x01\x12\n\n\x06STRING\x10\x02\x12\t\n\x05\x42YTES\x10\x03\x12\n\n\x06\x44OUBLE\x10\x04\x12\x08\n\x04\x42OOL\x10\x05\x12\x14\n\x10LIMIT_DEFINITION\x10\x07\x12\r\n\tLOG_LEVEL\x10\t\x12\x0f\n\x0bSTRING_LIST\x10\n\x12\r\n\tINT_RANGE\x10\x0b\x12\x0c\n\x08\x44URATION\x10\x0c\x42\x0b\n\t_draft_id\"?\n\tChangedBy\x12\x0f\n\x07user_id\x18\x01 \x01(\x03\x12\r\n\x05\x65mail\x18\x02 \x01(\t\x12\x12\n\napi_key_id\x18\x03 \x01(\t\"\xe4\x01\n\tConfigRow\x12\x1b\n\x0eproject_env_id\x18\x01 \x01(\x03H\x00\x88\x01\x01\x12(\n\x06values\x18\x02 \x03(\x0b\x32\x18.prefab.ConditionalValue\x12\x35\n\nproperties\x18\x03 \x03(\x0b\x32!.prefab.ConfigRow.PropertiesEntry\x1a\x46\n\x0fPropertiesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.prefab.ConfigValue:\x02\x38\x01\x42\x11\n\x0f_project_env_id\"[\n\x10\x43onditionalValue\x12#\n\x08\x63riteria\x18\x01 \x03(\x0b\x32\x11.prefab.Criterion\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.prefab.ConfigValue\"\x94\x03\n\tCriterion\x12\x15\n\rproperty_name\x18\x01 \x01(\t\x12\x35\n\x08operator\x18\x02 \x01(\x0e\x32#.prefab.Criterion.CriterionOperator\x12+\n\x0evalue_to_match\x18\x03 \x01(\x0b\x32\x13.prefab.ConfigValue\"\x8b\x02\n\x11\x43riterionOperator\x12\x0b\n\x07NOT_SET\x10\x00\x12\x11\n\rLOOKUP_KEY_IN\x10\x01\x12\x15\n\x11LOOKUP_KEY_NOT_IN\x10\x02\x12\n\n\x06IN_SEG\x10\x03\x12\x0e\n\nNOT_IN_SEG\x10\x04\x12\x0f\n\x0b\x41LWAYS_TRUE\x10\x05\x12\x12\n\x0ePROP_IS_ONE_OF\x10\x06\x12\x16\n\x12PROP_IS_NOT_ONE_OF\x10\x07\x12\x19\n\x15PROP_ENDS_WITH_ONE_OF\x10\x08\x12!\n\x1dPROP_DOES_NOT_END_WITH_ONE_OF\x10\t\x12\x16\n\x12HIERARCHICAL_MATCH\x10\n\x12\x10\n\x0cIN_INT_RANGE\x10\x0b\"\x89\x01\n\x07Loggers\x12\x1f\n\x07loggers\x18\x01 \x03(\x0b\x32\x0e.prefab.Logger\x12\x10\n\x08start_at\x18\x02 \x01(\x03\x12\x0e\n\x06\x65nd_at\x18\x03 \x01(\x03\x12\x15\n\rinstance_hash\x18\x04 \x01(\t\x12\x16\n\tnamespace\x18\x05 \x01(\tH\x00\x88\x01\x01\x42\x0c\n\n_namespace\"\xd9\x01\n\x06Logger\x12\x13\n\x0blogger_name\x18\x01 \x01(\t\x12\x13\n\x06traces\x18\x02 \x01(\x03H\x00\x88\x01\x01\x12\x13\n\x06\x64\x65\x62ugs\x18\x03 \x01(\x03H\x01\x88\x01\x01\x12\x12\n\x05infos\x18\x04 \x01(\x03H\x02\x88\x01\x01\x12\x12\n\x05warns\x18\x05 \x01(\x03H\x03\x88\x01\x01\x12\x13\n\x06\x65rrors\x18\x06 \x01(\x03H\x04\x88\x01\x01\x12\x13\n\x06\x66\x61tals\x18\x07 \x01(\x03H\x05\x88\x01\x01\x42\t\n\x07_tracesB\t\n\x07_debugsB\x08\n\x06_infosB\x08\n\x06_warnsB\t\n\x07_errorsB\t\n\x07_fatals\"\x16\n\x14LoggerReportResponse\"\xdb\x03\n\rLimitResponse\x12\x0e\n\x06passed\x18\x01 \x01(\x08\x12\x12\n\nexpires_at\x18\x02 \x01(\x03\x12\x16\n\x0e\x65nforced_group\x18\x03 \x01(\t\x12\x16\n\x0e\x63urrent_bucket\x18\x04 \x01(\x03\x12\x14\n\x0cpolicy_group\x18\x05 \x01(\t\x12;\n\x0bpolicy_name\x18\x06 \x01(\x0e\x32&.prefab.LimitResponse.LimitPolicyNames\x12\x14\n\x0cpolicy_limit\x18\x07 \x01(\x05\x12\x0e\n\x06\x61mount\x18\x08 \x01(\x03\x12\x16\n\x0elimit_reset_at\x18\t \x01(\x03\x12\x39\n\x0csafety_level\x18\n \x01(\x0e\x32#.prefab.LimitDefinition.SafetyLevel\"\xa9\x01\n\x10LimitPolicyNames\x12\x0b\n\x07NOT_SET\x10\x00\x12\x14\n\x10SECONDLY_ROLLING\x10\x01\x12\x14\n\x10MINUTELY_ROLLING\x10\x03\x12\x12\n\x0eHOURLY_ROLLING\x10\x05\x12\x11\n\rDAILY_ROLLING\x10\x07\x12\x13\n\x0fMONTHLY_ROLLING\x10\x08\x12\x0c\n\x08INFINITE\x10\t\x12\x12\n\x0eYEARLY_ROLLING\x10\n\"\x99\x02\n\x0cLimitRequest\x12\x12\n\naccount_id\x18\x01 \x01(\x03\x12\x16\n\x0e\x61\x63quire_amount\x18\x02 \x01(\x05\x12\x0e\n\x06groups\x18\x03 \x03(\t\x12:\n\x0elimit_combiner\x18\x04 \x01(\x0e\x32\".prefab.LimitRequest.LimitCombiner\x12\x1e\n\x16\x61llow_partial_response\x18\x05 \x01(\x08\x12\x39\n\x0csafety_level\x18\x06 \x01(\x0e\x32#.prefab.LimitDefinition.SafetyLevel\"6\n\rLimitCombiner\x12\x0b\n\x07NOT_SET\x10\x00\x12\x0b\n\x07MINIMUM\x10\x01\x12\x0b\n\x07MAXIMUM\x10\x02\"/\n\nContextSet\x12!\n\x08\x63ontexts\x18\x01 \x03(\x0b\x32\x0f.prefab.Context\"\x96\x01\n\x07\x43ontext\x12\x11\n\x04type\x18\x01 \x01(\tH\x00\x88\x01\x01\x12+\n\x06values\x18\x02 \x03(\x0b\x32\x1b.prefab.Context.ValuesEntry\x1a\x42\n\x0bValuesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.prefab.ConfigValue:\x02\x38\x01\x42\x07\n\x05_type\"\x93\x01\n\x08Identity\x12\x13\n\x06lookup\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x34\n\nattributes\x18\x02 \x03(\x0b\x32 .prefab.Identity.AttributesEntry\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\t\n\x07_lookup\"\xd6\x02\n\x18\x43onfigEvaluationMetaData\x12\x1d\n\x10\x63onfig_row_index\x18\x01 \x01(\x03H\x00\x88\x01\x01\x12$\n\x17\x63onditional_value_index\x18\x02 \x01(\x03H\x01\x88\x01\x01\x12!\n\x14weighted_value_index\x18\x03 \x01(\x03H\x02\x88\x01\x01\x12%\n\x04type\x18\x04 \x01(\x0e\x32\x12.prefab.ConfigTypeH\x03\x88\x01\x01\x12\x0f\n\x02id\x18\x05 \x01(\x03H\x04\x88\x01\x01\x12\x31\n\nvalue_type\x18\x06 \x01(\x0e\x32\x18.prefab.Config.ValueTypeH\x05\x88\x01\x01\x42\x13\n\x11_config_row_indexB\x1a\n\x18_conditional_value_indexB\x17\n\x15_weighted_value_indexB\x07\n\x05_typeB\x05\n\x03_idB\r\n\x0b_value_type\"\xed\x02\n\x11\x43lientConfigValue\x12\r\n\x03int\x18\x01 \x01(\x03H\x00\x12\x10\n\x06string\x18\x02 \x01(\tH\x00\x12\x10\n\x06\x64ouble\x18\x03 \x01(\x01H\x00\x12\x0e\n\x04\x62ool\x18\x04 \x01(\x08H\x00\x12%\n\tlog_level\x18\x05 \x01(\x0e\x32\x10.prefab.LogLevelH\x00\x12)\n\x0bstring_list\x18\x07 \x01(\x0b\x32\x12.prefab.StringListH\x00\x12%\n\tint_range\x18\x08 \x01(\x0b\x32\x10.prefab.IntRangeH\x00\x12*\n\x08\x64uration\x18\t \x01(\x0b\x32\x16.prefab.ClientDurationH\x00\x12I\n\x1a\x63onfig_evaluation_metadata\x18\x06 \x01(\x0b\x32 .prefab.ConfigEvaluationMetaDataH\x01\x88\x01\x01\x42\x06\n\x04typeB\x1d\n\x1b_config_evaluation_metadata\"0\n\x0e\x43lientDuration\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\"\xa4\x02\n\x11\x43onfigEvaluations\x12\x35\n\x06values\x18\x01 \x03(\x0b\x32%.prefab.ConfigEvaluations.ValuesEntry\x12\x34\n\x0f\x61pikey_metadata\x18\x02 \x01(\x0b\x32\x16.prefab.ApiKeyMetadataH\x00\x88\x01\x01\x12\x30\n\x0f\x64\x65\x66\x61ult_context\x18\x03 \x01(\x0b\x32\x12.prefab.ContextSetH\x01\x88\x01\x01\x1aH\n\x0bValuesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12(\n\x05value\x18\x02 \x01(\x0b\x32\x19.prefab.ClientConfigValue:\x02\x38\x01\x42\x12\n\x10_apikey_metadataB\x12\n\x10_default_context\"\xa8\x02\n\x0fLimitDefinition\x12;\n\x0bpolicy_name\x18\x02 \x01(\x0e\x32&.prefab.LimitResponse.LimitPolicyNames\x12\r\n\x05limit\x18\x03 \x01(\x05\x12\r\n\x05\x62urst\x18\x04 \x01(\x05\x12\x12\n\naccount_id\x18\x05 \x01(\x03\x12\x15\n\rlast_modified\x18\x06 \x01(\x03\x12\x12\n\nreturnable\x18\x07 \x01(\x08\x12\x39\n\x0csafety_level\x18\x08 \x01(\x0e\x32#.prefab.LimitDefinition.SafetyLevel\"@\n\x0bSafetyLevel\x12\x0b\n\x07NOT_SET\x10\x00\x12\x12\n\x0eL4_BEST_EFFORT\x10\x04\x12\x10\n\x0cL5_BOMBPROOF\x10\x05\"@\n\x10LimitDefinitions\x12,\n\x0b\x64\x65\x66initions\x18\x01 \x03(\x0b\x32\x17.prefab.LimitDefinition\"\x8a\x01\n\x0f\x42ufferedRequest\x12\x12\n\naccount_id\x18\x01 \x01(\x03\x12\x0e\n\x06method\x18\x02 \x01(\t\x12\x0b\n\x03uri\x18\x03 \x01(\t\x12\x0c\n\x04\x62ody\x18\x04 \x01(\t\x12\x14\n\x0climit_groups\x18\x05 \x03(\t\x12\x14\n\x0c\x63ontent_type\x18\x06 \x01(\t\x12\x0c\n\x04\x66ifo\x18\x07 \x01(\x08\"\x94\x01\n\x0c\x42\x61tchRequest\x12\x12\n\naccount_id\x18\x01 \x01(\x03\x12\x0e\n\x06method\x18\x02 \x01(\t\x12\x0b\n\x03uri\x18\x03 \x01(\t\x12\x0c\n\x04\x62ody\x18\x04 \x01(\t\x12\x14\n\x0climit_groups\x18\x05 \x03(\t\x12\x16\n\x0e\x62\x61tch_template\x18\x06 \x01(\t\x12\x17\n\x0f\x62\x61tch_separator\x18\x07 \x01(\t\" \n\rBasicResponse\x12\x0f\n\x07message\x18\x01 \x01(\t\"3\n\x10\x43reationResponse\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x0e\n\x06new_id\x18\x02 \x01(\x03\"h\n\x07IdBlock\x12\x12\n\nproject_id\x18\x01 \x01(\x03\x12\x16\n\x0eproject_env_id\x18\x02 \x01(\x03\x12\x15\n\rsequence_name\x18\x03 \x01(\t\x12\r\n\x05start\x18\x04 \x01(\x03\x12\x0b\n\x03\x65nd\x18\x05 \x01(\x03\"a\n\x0eIdBlockRequest\x12\x12\n\nproject_id\x18\x01 \x01(\x03\x12\x16\n\x0eproject_env_id\x18\x02 \x01(\x03\x12\x15\n\rsequence_name\x18\x03 \x01(\t\x12\x0c\n\x04size\x18\x04 \x01(\x03\"\x8a\x01\n\x0c\x43ontextShape\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x39\n\x0b\x66ield_types\x18\x02 \x03(\x0b\x32$.prefab.ContextShape.FieldTypesEntry\x1a\x31\n\x0f\x46ieldTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"[\n\rContextShapes\x12$\n\x06shapes\x18\x01 \x03(\x0b\x32\x14.prefab.ContextShape\x12\x16\n\tnamespace\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0c\n\n_namespace\"C\n\rEvaluatedKeys\x12\x0c\n\x04keys\x18\x01 \x03(\t\x12\x16\n\tnamespace\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0c\n\n_namespace\"\x93\x01\n\x0f\x45valuatedConfig\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x16\n\x0e\x63onfig_version\x18\x02 \x01(\x03\x12#\n\x06result\x18\x03 \x01(\x0b\x32\x13.prefab.ConfigValue\x12#\n\x07\x63ontext\x18\x04 \x01(\x0b\x32\x12.prefab.ContextSet\x12\x11\n\ttimestamp\x18\x05 \x01(\x03\"<\n\x10\x45valuatedConfigs\x12(\n\x07\x63onfigs\x18\x01 \x03(\x0b\x32\x17.prefab.EvaluatedConfig\"\xc4\x03\n\x17\x43onfigEvaluationCounter\x12\r\n\x05\x63ount\x18\x01 \x01(\x03\x12\x16\n\tconfig_id\x18\x02 \x01(\x03H\x00\x88\x01\x01\x12\x1b\n\x0eselected_index\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x30\n\x0eselected_value\x18\x04 \x01(\x0b\x32\x13.prefab.ConfigValueH\x02\x88\x01\x01\x12\x1d\n\x10\x63onfig_row_index\x18\x05 \x01(\rH\x03\x88\x01\x01\x12$\n\x17\x63onditional_value_index\x18\x06 \x01(\rH\x04\x88\x01\x01\x12!\n\x14weighted_value_index\x18\x07 \x01(\rH\x05\x88\x01\x01\x12\x36\n\x06reason\x18\x08 \x01(\x0e\x32&.prefab.ConfigEvaluationCounter.Reason\"\x15\n\x06Reason\x12\x0b\n\x07UNKNOWN\x10\x00\x42\x0c\n\n_config_idB\x11\n\x0f_selected_indexB\x11\n\x0f_selected_valueB\x13\n\x11_config_row_indexB\x1a\n\x18_conditional_value_indexB\x17\n\x15_weighted_value_index\"{\n\x17\x43onfigEvaluationSummary\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x04type\x18\x02 \x01(\x0e\x32\x12.prefab.ConfigType\x12\x31\n\x08\x63ounters\x18\x03 \x03(\x0b\x32\x1f.prefab.ConfigEvaluationCounter\"k\n\x19\x43onfigEvaluationSummaries\x12\r\n\x05start\x18\x01 \x01(\x03\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x03\x12\x32\n\tsummaries\x18\x03 \x03(\x0b\x32\x1f.prefab.ConfigEvaluationSummary\"Z\n\x15LoggersTelemetryEvent\x12\x1f\n\x07loggers\x18\x01 \x03(\x0b\x32\x0e.prefab.Logger\x12\x10\n\x08start_at\x18\x02 \x01(\x03\x12\x0e\n\x06\x65nd_at\x18\x03 \x01(\x03\"\x98\x02\n\x0eTelemetryEvent\x12\x36\n\tsummaries\x18\x02 \x01(\x0b\x32!.prefab.ConfigEvaluationSummariesH\x00\x12\x33\n\x10\x65xample_contexts\x18\x03 \x01(\x0b\x32\x17.prefab.ExampleContextsH\x00\x12+\n\x0c\x63lient_stats\x18\x04 \x01(\x0b\x32\x13.prefab.ClientStatsH\x00\x12\x30\n\x07loggers\x18\x05 \x01(\x0b\x32\x1d.prefab.LoggersTelemetryEventH\x00\x12/\n\x0e\x63ontext_shapes\x18\x06 \x01(\x0b\x32\x15.prefab.ContextShapesH\x00\x42\t\n\x07payload\"P\n\x0fTelemetryEvents\x12\x15\n\rinstance_hash\x18\x01 \x01(\t\x12&\n\x06\x65vents\x18\x02 \x03(\x0b\x32\x16.prefab.TelemetryEvent\"*\n\x17TelemetryEventsResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\";\n\x0f\x45xampleContexts\x12(\n\x08\x65xamples\x18\x01 \x03(\x0b\x32\x16.prefab.ExampleContext\"K\n\x0e\x45xampleContext\x12\x11\n\ttimestamp\x18\x01 \x01(\x03\x12&\n\ncontextSet\x18\x02 \x01(\x0b\x32\x12.prefab.ContextSet\"F\n\x0b\x43lientStats\x12\r\n\x05start\x18\x01 \x01(\x03\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x03\x12\x1b\n\x13\x64ropped_event_count\x18\x03 \x01(\x04*:\n\x0eProvidedSource\x12\x1b\n\x17PROVIDED_SOURCE_NOT_SET\x10\x00\x12\x0b\n\x07\x45NV_VAR\x10\x01*\x82\x01\n\nConfigType\x12\x17\n\x13NOT_SET_CONFIG_TYPE\x10\x00\x12\n\n\x06\x43ONFIG\x10\x01\x12\x10\n\x0c\x46\x45\x41TURE_FLAG\x10\x02\x12\r\n\tLOG_LEVEL\x10\x03\x12\x0b\n\x07SEGMENT\x10\x04\x12\x14\n\x10LIMIT_DEFINITION\x10\x05\x12\x0b\n\x07\x44\x45LETED\x10\x06*a\n\x08LogLevel\x12\x15\n\x11NOT_SET_LOG_LEVEL\x10\x00\x12\t\n\x05TRACE\x10\x01\x12\t\n\x05\x44\x45\x42UG\x10\x02\x12\x08\n\x04INFO\x10\x03\x12\x08\n\x04WARN\x10\x05\x12\t\n\x05\x45RROR\x10\x06\x12\t\n\x05\x46\x41TAL\x10\t*G\n\tOnFailure\x12\x0b\n\x07NOT_SET\x10\x00\x12\x10\n\x0cLOG_AND_PASS\x10\x01\x12\x10\n\x0cLOG_AND_FAIL\x10\x02\x12\t\n\x05THROW\x10\x03\x42L\n\x13\x63loud.prefab.domainB\x06PrefabZ-github.com/prefab-cloud/prefab-cloud-go/protob\x06proto3"
8
+ descriptor_data = "\n\x0cprefab.proto\x12\x06prefab\"W\n\x14\x43onfigServicePointer\x12\x12\n\nproject_id\x18\x01 \x01(\x03\x12\x13\n\x0bstart_at_id\x18\x02 \x01(\x03\x12\x16\n\x0eproject_env_id\x18\x03 \x01(\x03\"\x8f\x04\n\x0b\x43onfigValue\x12\r\n\x03int\x18\x01 \x01(\x03H\x00\x12\x10\n\x06string\x18\x02 \x01(\tH\x00\x12\x0f\n\x05\x62ytes\x18\x03 \x01(\x0cH\x00\x12\x10\n\x06\x64ouble\x18\x04 \x01(\x01H\x00\x12\x0e\n\x04\x62ool\x18\x05 \x01(\x08H\x00\x12\x31\n\x0fweighted_values\x18\x06 \x01(\x0b\x32\x16.prefab.WeightedValuesH\x00\x12\x33\n\x10limit_definition\x18\x07 \x01(\x0b\x32\x17.prefab.LimitDefinitionH\x00\x12%\n\tlog_level\x18\t \x01(\x0e\x32\x10.prefab.LogLevelH\x00\x12)\n\x0bstring_list\x18\n \x01(\x0b\x32\x12.prefab.StringListH\x00\x12%\n\tint_range\x18\x0b \x01(\x0b\x32\x10.prefab.IntRangeH\x00\x12$\n\x08provided\x18\x0c \x01(\x0b\x32\x10.prefab.ProvidedH\x00\x12\'\n\x08\x64uration\x18\x0f \x01(\x0b\x32\x13.prefab.IsoDurationH\x00\x12\x1c\n\x04json\x18\x10 \x01(\x0b\x32\x0c.prefab.JsonH\x00\x12\x19\n\x0c\x63onfidential\x18\r \x01(\x08H\x01\x88\x01\x01\x12\x19\n\x0c\x64\x65\x63rypt_with\x18\x0e \x01(\tH\x02\x88\x01\x01\x42\x06\n\x04typeB\x0f\n\r_confidentialB\x0f\n\r_decrypt_with\"\x14\n\x04Json\x12\x0c\n\x04json\x18\x01 \x01(\t\"!\n\x0bIsoDuration\x12\x12\n\ndefinition\x18\x01 \x01(\t\"b\n\x08Provided\x12+\n\x06source\x18\x01 \x01(\x0e\x32\x16.prefab.ProvidedSourceH\x00\x88\x01\x01\x12\x13\n\x06lookup\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\t\n\x07_sourceB\t\n\x07_lookup\"B\n\x08IntRange\x12\x12\n\x05start\x18\x01 \x01(\x03H\x00\x88\x01\x01\x12\x10\n\x03\x65nd\x18\x02 \x01(\x03H\x01\x88\x01\x01\x42\x08\n\x06_startB\x06\n\x04_end\"\x1c\n\nStringList\x12\x0e\n\x06values\x18\x01 \x03(\t\"C\n\rWeightedValue\x12\x0e\n\x06weight\x18\x01 \x01(\x05\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.prefab.ConfigValue\"~\n\x0eWeightedValues\x12.\n\x0fweighted_values\x18\x01 \x03(\x0b\x32\x15.prefab.WeightedValue\x12\"\n\x15hash_by_property_name\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x18\n\x16_hash_by_property_name\"X\n\x0e\x41piKeyMetadata\x12\x13\n\x06key_id\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x07user_id\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\t\n\x07_key_idB\n\n\x08_user_idJ\x04\x08\x02\x10\x03\"\xa0\x02\n\x07\x43onfigs\x12\x1f\n\x07\x63onfigs\x18\x01 \x03(\x0b\x32\x0e.prefab.Config\x12<\n\x16\x63onfig_service_pointer\x18\x02 \x01(\x0b\x32\x1c.prefab.ConfigServicePointer\x12\x34\n\x0f\x61pikey_metadata\x18\x03 \x01(\x0b\x32\x16.prefab.ApiKeyMetadataH\x00\x88\x01\x01\x12\x30\n\x0f\x64\x65\x66\x61ult_context\x18\x04 \x01(\x0b\x32\x12.prefab.ContextSetH\x01\x88\x01\x01\x12\x17\n\nkeep_alive\x18\x05 \x01(\x08H\x02\x88\x01\x01\x42\x12\n\x10_apikey_metadataB\x12\n\x10_default_contextB\r\n\x0b_keep_alive\"\xfc\x03\n\x06\x43onfig\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x12\n\nproject_id\x18\x02 \x01(\x03\x12\x0b\n\x03key\x18\x03 \x01(\t\x12%\n\nchanged_by\x18\x04 \x01(\x0b\x32\x11.prefab.ChangedBy\x12\x1f\n\x04rows\x18\x05 \x03(\x0b\x32\x11.prefab.ConfigRow\x12-\n\x10\x61llowable_values\x18\x06 \x03(\x0b\x32\x13.prefab.ConfigValue\x12\'\n\x0b\x63onfig_type\x18\x07 \x01(\x0e\x32\x12.prefab.ConfigType\x12\x15\n\x08\x64raft_id\x18\x08 \x01(\x03H\x00\x88\x01\x01\x12,\n\nvalue_type\x18\t \x01(\x0e\x32\x18.prefab.Config.ValueType\x12\x1a\n\x12send_to_client_sdk\x18\n \x01(\x08\"\xb6\x01\n\tValueType\x12\x16\n\x12NOT_SET_VALUE_TYPE\x10\x00\x12\x07\n\x03INT\x10\x01\x12\n\n\x06STRING\x10\x02\x12\t\n\x05\x42YTES\x10\x03\x12\n\n\x06\x44OUBLE\x10\x04\x12\x08\n\x04\x42OOL\x10\x05\x12\x14\n\x10LIMIT_DEFINITION\x10\x07\x12\r\n\tLOG_LEVEL\x10\t\x12\x0f\n\x0bSTRING_LIST\x10\n\x12\r\n\tINT_RANGE\x10\x0b\x12\x0c\n\x08\x44URATION\x10\x0c\x12\x08\n\x04JSON\x10\rB\x0b\n\t_draft_id\"?\n\tChangedBy\x12\x0f\n\x07user_id\x18\x01 \x01(\x03\x12\r\n\x05\x65mail\x18\x02 \x01(\t\x12\x12\n\napi_key_id\x18\x03 \x01(\t\"\xe4\x01\n\tConfigRow\x12\x1b\n\x0eproject_env_id\x18\x01 \x01(\x03H\x00\x88\x01\x01\x12(\n\x06values\x18\x02 \x03(\x0b\x32\x18.prefab.ConditionalValue\x12\x35\n\nproperties\x18\x03 \x03(\x0b\x32!.prefab.ConfigRow.PropertiesEntry\x1a\x46\n\x0fPropertiesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.prefab.ConfigValue:\x02\x38\x01\x42\x11\n\x0f_project_env_id\"[\n\x10\x43onditionalValue\x12#\n\x08\x63riteria\x18\x01 \x03(\x0b\x32\x11.prefab.Criterion\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.prefab.ConfigValue\"\x94\x03\n\tCriterion\x12\x15\n\rproperty_name\x18\x01 \x01(\t\x12\x35\n\x08operator\x18\x02 \x01(\x0e\x32#.prefab.Criterion.CriterionOperator\x12+\n\x0evalue_to_match\x18\x03 \x01(\x0b\x32\x13.prefab.ConfigValue\"\x8b\x02\n\x11\x43riterionOperator\x12\x0b\n\x07NOT_SET\x10\x00\x12\x11\n\rLOOKUP_KEY_IN\x10\x01\x12\x15\n\x11LOOKUP_KEY_NOT_IN\x10\x02\x12\n\n\x06IN_SEG\x10\x03\x12\x0e\n\nNOT_IN_SEG\x10\x04\x12\x0f\n\x0b\x41LWAYS_TRUE\x10\x05\x12\x12\n\x0ePROP_IS_ONE_OF\x10\x06\x12\x16\n\x12PROP_IS_NOT_ONE_OF\x10\x07\x12\x19\n\x15PROP_ENDS_WITH_ONE_OF\x10\x08\x12!\n\x1dPROP_DOES_NOT_END_WITH_ONE_OF\x10\t\x12\x16\n\x12HIERARCHICAL_MATCH\x10\n\x12\x10\n\x0cIN_INT_RANGE\x10\x0b\"\x89\x01\n\x07Loggers\x12\x1f\n\x07loggers\x18\x01 \x03(\x0b\x32\x0e.prefab.Logger\x12\x10\n\x08start_at\x18\x02 \x01(\x03\x12\x0e\n\x06\x65nd_at\x18\x03 \x01(\x03\x12\x15\n\rinstance_hash\x18\x04 \x01(\t\x12\x16\n\tnamespace\x18\x05 \x01(\tH\x00\x88\x01\x01\x42\x0c\n\n_namespace\"\xd9\x01\n\x06Logger\x12\x13\n\x0blogger_name\x18\x01 \x01(\t\x12\x13\n\x06traces\x18\x02 \x01(\x03H\x00\x88\x01\x01\x12\x13\n\x06\x64\x65\x62ugs\x18\x03 \x01(\x03H\x01\x88\x01\x01\x12\x12\n\x05infos\x18\x04 \x01(\x03H\x02\x88\x01\x01\x12\x12\n\x05warns\x18\x05 \x01(\x03H\x03\x88\x01\x01\x12\x13\n\x06\x65rrors\x18\x06 \x01(\x03H\x04\x88\x01\x01\x12\x13\n\x06\x66\x61tals\x18\x07 \x01(\x03H\x05\x88\x01\x01\x42\t\n\x07_tracesB\t\n\x07_debugsB\x08\n\x06_infosB\x08\n\x06_warnsB\t\n\x07_errorsB\t\n\x07_fatals\"\x16\n\x14LoggerReportResponse\"\xdb\x03\n\rLimitResponse\x12\x0e\n\x06passed\x18\x01 \x01(\x08\x12\x12\n\nexpires_at\x18\x02 \x01(\x03\x12\x16\n\x0e\x65nforced_group\x18\x03 \x01(\t\x12\x16\n\x0e\x63urrent_bucket\x18\x04 \x01(\x03\x12\x14\n\x0cpolicy_group\x18\x05 \x01(\t\x12;\n\x0bpolicy_name\x18\x06 \x01(\x0e\x32&.prefab.LimitResponse.LimitPolicyNames\x12\x14\n\x0cpolicy_limit\x18\x07 \x01(\x05\x12\x0e\n\x06\x61mount\x18\x08 \x01(\x03\x12\x16\n\x0elimit_reset_at\x18\t \x01(\x03\x12\x39\n\x0csafety_level\x18\n \x01(\x0e\x32#.prefab.LimitDefinition.SafetyLevel\"\xa9\x01\n\x10LimitPolicyNames\x12\x0b\n\x07NOT_SET\x10\x00\x12\x14\n\x10SECONDLY_ROLLING\x10\x01\x12\x14\n\x10MINUTELY_ROLLING\x10\x03\x12\x12\n\x0eHOURLY_ROLLING\x10\x05\x12\x11\n\rDAILY_ROLLING\x10\x07\x12\x13\n\x0fMONTHLY_ROLLING\x10\x08\x12\x0c\n\x08INFINITE\x10\t\x12\x12\n\x0eYEARLY_ROLLING\x10\n\"\x99\x02\n\x0cLimitRequest\x12\x12\n\naccount_id\x18\x01 \x01(\x03\x12\x16\n\x0e\x61\x63quire_amount\x18\x02 \x01(\x05\x12\x0e\n\x06groups\x18\x03 \x03(\t\x12:\n\x0elimit_combiner\x18\x04 \x01(\x0e\x32\".prefab.LimitRequest.LimitCombiner\x12\x1e\n\x16\x61llow_partial_response\x18\x05 \x01(\x08\x12\x39\n\x0csafety_level\x18\x06 \x01(\x0e\x32#.prefab.LimitDefinition.SafetyLevel\"6\n\rLimitCombiner\x12\x0b\n\x07NOT_SET\x10\x00\x12\x0b\n\x07MINIMUM\x10\x01\x12\x0b\n\x07MAXIMUM\x10\x02\"/\n\nContextSet\x12!\n\x08\x63ontexts\x18\x01 \x03(\x0b\x32\x0f.prefab.Context\"\x96\x01\n\x07\x43ontext\x12\x11\n\x04type\x18\x01 \x01(\tH\x00\x88\x01\x01\x12+\n\x06values\x18\x02 \x03(\x0b\x32\x1b.prefab.Context.ValuesEntry\x1a\x42\n\x0bValuesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.prefab.ConfigValue:\x02\x38\x01\x42\x07\n\x05_type\"\x93\x01\n\x08Identity\x12\x13\n\x06lookup\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x34\n\nattributes\x18\x02 \x03(\x0b\x32 .prefab.Identity.AttributesEntry\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\t\n\x07_lookup\"\xd6\x02\n\x18\x43onfigEvaluationMetaData\x12\x1d\n\x10\x63onfig_row_index\x18\x01 \x01(\x03H\x00\x88\x01\x01\x12$\n\x17\x63onditional_value_index\x18\x02 \x01(\x03H\x01\x88\x01\x01\x12!\n\x14weighted_value_index\x18\x03 \x01(\x03H\x02\x88\x01\x01\x12%\n\x04type\x18\x04 \x01(\x0e\x32\x12.prefab.ConfigTypeH\x03\x88\x01\x01\x12\x0f\n\x02id\x18\x05 \x01(\x03H\x04\x88\x01\x01\x12\x31\n\nvalue_type\x18\x06 \x01(\x0e\x32\x18.prefab.Config.ValueTypeH\x05\x88\x01\x01\x42\x13\n\x11_config_row_indexB\x1a\n\x18_conditional_value_indexB\x17\n\x15_weighted_value_indexB\x07\n\x05_typeB\x05\n\x03_idB\r\n\x0b_value_type\"\x8b\x03\n\x11\x43lientConfigValue\x12\r\n\x03int\x18\x01 \x01(\x03H\x00\x12\x10\n\x06string\x18\x02 \x01(\tH\x00\x12\x10\n\x06\x64ouble\x18\x03 \x01(\x01H\x00\x12\x0e\n\x04\x62ool\x18\x04 \x01(\x08H\x00\x12%\n\tlog_level\x18\x05 \x01(\x0e\x32\x10.prefab.LogLevelH\x00\x12)\n\x0bstring_list\x18\x07 \x01(\x0b\x32\x12.prefab.StringListH\x00\x12%\n\tint_range\x18\x08 \x01(\x0b\x32\x10.prefab.IntRangeH\x00\x12*\n\x08\x64uration\x18\t \x01(\x0b\x32\x16.prefab.ClientDurationH\x00\x12\x1c\n\x04json\x18\n \x01(\x0b\x32\x0c.prefab.JsonH\x00\x12I\n\x1a\x63onfig_evaluation_metadata\x18\x06 \x01(\x0b\x32 .prefab.ConfigEvaluationMetaDataH\x01\x88\x01\x01\x42\x06\n\x04typeB\x1d\n\x1b_config_evaluation_metadata\"D\n\x0e\x43lientDuration\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x12\x12\n\ndefinition\x18\x03 \x01(\t\"\xa4\x02\n\x11\x43onfigEvaluations\x12\x35\n\x06values\x18\x01 \x03(\x0b\x32%.prefab.ConfigEvaluations.ValuesEntry\x12\x34\n\x0f\x61pikey_metadata\x18\x02 \x01(\x0b\x32\x16.prefab.ApiKeyMetadataH\x00\x88\x01\x01\x12\x30\n\x0f\x64\x65\x66\x61ult_context\x18\x03 \x01(\x0b\x32\x12.prefab.ContextSetH\x01\x88\x01\x01\x1aH\n\x0bValuesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12(\n\x05value\x18\x02 \x01(\x0b\x32\x19.prefab.ClientConfigValue:\x02\x38\x01\x42\x12\n\x10_apikey_metadataB\x12\n\x10_default_context\"\xa8\x02\n\x0fLimitDefinition\x12;\n\x0bpolicy_name\x18\x02 \x01(\x0e\x32&.prefab.LimitResponse.LimitPolicyNames\x12\r\n\x05limit\x18\x03 \x01(\x05\x12\r\n\x05\x62urst\x18\x04 \x01(\x05\x12\x12\n\naccount_id\x18\x05 \x01(\x03\x12\x15\n\rlast_modified\x18\x06 \x01(\x03\x12\x12\n\nreturnable\x18\x07 \x01(\x08\x12\x39\n\x0csafety_level\x18\x08 \x01(\x0e\x32#.prefab.LimitDefinition.SafetyLevel\"@\n\x0bSafetyLevel\x12\x0b\n\x07NOT_SET\x10\x00\x12\x12\n\x0eL4_BEST_EFFORT\x10\x04\x12\x10\n\x0cL5_BOMBPROOF\x10\x05\"@\n\x10LimitDefinitions\x12,\n\x0b\x64\x65\x66initions\x18\x01 \x03(\x0b\x32\x17.prefab.LimitDefinition\"\x8a\x01\n\x0f\x42ufferedRequest\x12\x12\n\naccount_id\x18\x01 \x01(\x03\x12\x0e\n\x06method\x18\x02 \x01(\t\x12\x0b\n\x03uri\x18\x03 \x01(\t\x12\x0c\n\x04\x62ody\x18\x04 \x01(\t\x12\x14\n\x0climit_groups\x18\x05 \x03(\t\x12\x14\n\x0c\x63ontent_type\x18\x06 \x01(\t\x12\x0c\n\x04\x66ifo\x18\x07 \x01(\x08\"\x94\x01\n\x0c\x42\x61tchRequest\x12\x12\n\naccount_id\x18\x01 \x01(\x03\x12\x0e\n\x06method\x18\x02 \x01(\t\x12\x0b\n\x03uri\x18\x03 \x01(\t\x12\x0c\n\x04\x62ody\x18\x04 \x01(\t\x12\x14\n\x0climit_groups\x18\x05 \x03(\t\x12\x16\n\x0e\x62\x61tch_template\x18\x06 \x01(\t\x12\x17\n\x0f\x62\x61tch_separator\x18\x07 \x01(\t\" \n\rBasicResponse\x12\x0f\n\x07message\x18\x01 \x01(\t\"3\n\x10\x43reationResponse\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x0e\n\x06new_id\x18\x02 \x01(\x03\"h\n\x07IdBlock\x12\x12\n\nproject_id\x18\x01 \x01(\x03\x12\x16\n\x0eproject_env_id\x18\x02 \x01(\x03\x12\x15\n\rsequence_name\x18\x03 \x01(\t\x12\r\n\x05start\x18\x04 \x01(\x03\x12\x0b\n\x03\x65nd\x18\x05 \x01(\x03\"a\n\x0eIdBlockRequest\x12\x12\n\nproject_id\x18\x01 \x01(\x03\x12\x16\n\x0eproject_env_id\x18\x02 \x01(\x03\x12\x15\n\rsequence_name\x18\x03 \x01(\t\x12\x0c\n\x04size\x18\x04 \x01(\x03\"\x8a\x01\n\x0c\x43ontextShape\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x39\n\x0b\x66ield_types\x18\x02 \x03(\x0b\x32$.prefab.ContextShape.FieldTypesEntry\x1a\x31\n\x0f\x46ieldTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"[\n\rContextShapes\x12$\n\x06shapes\x18\x01 \x03(\x0b\x32\x14.prefab.ContextShape\x12\x16\n\tnamespace\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0c\n\n_namespace\"C\n\rEvaluatedKeys\x12\x0c\n\x04keys\x18\x01 \x03(\t\x12\x16\n\tnamespace\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0c\n\n_namespace\"\x93\x01\n\x0f\x45valuatedConfig\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x16\n\x0e\x63onfig_version\x18\x02 \x01(\x03\x12#\n\x06result\x18\x03 \x01(\x0b\x32\x13.prefab.ConfigValue\x12#\n\x07\x63ontext\x18\x04 \x01(\x0b\x32\x12.prefab.ContextSet\x12\x11\n\ttimestamp\x18\x05 \x01(\x03\"<\n\x10\x45valuatedConfigs\x12(\n\x07\x63onfigs\x18\x01 \x03(\x0b\x32\x17.prefab.EvaluatedConfig\"\xc4\x03\n\x17\x43onfigEvaluationCounter\x12\r\n\x05\x63ount\x18\x01 \x01(\x03\x12\x16\n\tconfig_id\x18\x02 \x01(\x03H\x00\x88\x01\x01\x12\x1b\n\x0eselected_index\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x30\n\x0eselected_value\x18\x04 \x01(\x0b\x32\x13.prefab.ConfigValueH\x02\x88\x01\x01\x12\x1d\n\x10\x63onfig_row_index\x18\x05 \x01(\rH\x03\x88\x01\x01\x12$\n\x17\x63onditional_value_index\x18\x06 \x01(\rH\x04\x88\x01\x01\x12!\n\x14weighted_value_index\x18\x07 \x01(\rH\x05\x88\x01\x01\x12\x36\n\x06reason\x18\x08 \x01(\x0e\x32&.prefab.ConfigEvaluationCounter.Reason\"\x15\n\x06Reason\x12\x0b\n\x07UNKNOWN\x10\x00\x42\x0c\n\n_config_idB\x11\n\x0f_selected_indexB\x11\n\x0f_selected_valueB\x13\n\x11_config_row_indexB\x1a\n\x18_conditional_value_indexB\x17\n\x15_weighted_value_index\"{\n\x17\x43onfigEvaluationSummary\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x04type\x18\x02 \x01(\x0e\x32\x12.prefab.ConfigType\x12\x31\n\x08\x63ounters\x18\x03 \x03(\x0b\x32\x1f.prefab.ConfigEvaluationCounter\"k\n\x19\x43onfigEvaluationSummaries\x12\r\n\x05start\x18\x01 \x01(\x03\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x03\x12\x32\n\tsummaries\x18\x03 \x03(\x0b\x32\x1f.prefab.ConfigEvaluationSummary\"Z\n\x15LoggersTelemetryEvent\x12\x1f\n\x07loggers\x18\x01 \x03(\x0b\x32\x0e.prefab.Logger\x12\x10\n\x08start_at\x18\x02 \x01(\x03\x12\x0e\n\x06\x65nd_at\x18\x03 \x01(\x03\"\x98\x02\n\x0eTelemetryEvent\x12\x36\n\tsummaries\x18\x02 \x01(\x0b\x32!.prefab.ConfigEvaluationSummariesH\x00\x12\x33\n\x10\x65xample_contexts\x18\x03 \x01(\x0b\x32\x17.prefab.ExampleContextsH\x00\x12+\n\x0c\x63lient_stats\x18\x04 \x01(\x0b\x32\x13.prefab.ClientStatsH\x00\x12\x30\n\x07loggers\x18\x05 \x01(\x0b\x32\x1d.prefab.LoggersTelemetryEventH\x00\x12/\n\x0e\x63ontext_shapes\x18\x06 \x01(\x0b\x32\x15.prefab.ContextShapesH\x00\x42\t\n\x07payload\"P\n\x0fTelemetryEvents\x12\x15\n\rinstance_hash\x18\x01 \x01(\t\x12&\n\x06\x65vents\x18\x02 \x03(\x0b\x32\x16.prefab.TelemetryEvent\"*\n\x17TelemetryEventsResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\";\n\x0f\x45xampleContexts\x12(\n\x08\x65xamples\x18\x01 \x03(\x0b\x32\x16.prefab.ExampleContext\"K\n\x0e\x45xampleContext\x12\x11\n\ttimestamp\x18\x01 \x01(\x03\x12&\n\ncontextSet\x18\x02 \x01(\x0b\x32\x12.prefab.ContextSet\"F\n\x0b\x43lientStats\x12\r\n\x05start\x18\x01 \x01(\x03\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x03\x12\x1b\n\x13\x64ropped_event_count\x18\x03 \x01(\x04*:\n\x0eProvidedSource\x12\x1b\n\x17PROVIDED_SOURCE_NOT_SET\x10\x00\x12\x0b\n\x07\x45NV_VAR\x10\x01*\x82\x01\n\nConfigType\x12\x17\n\x13NOT_SET_CONFIG_TYPE\x10\x00\x12\n\n\x06\x43ONFIG\x10\x01\x12\x10\n\x0c\x46\x45\x41TURE_FLAG\x10\x02\x12\r\n\tLOG_LEVEL\x10\x03\x12\x0b\n\x07SEGMENT\x10\x04\x12\x14\n\x10LIMIT_DEFINITION\x10\x05\x12\x0b\n\x07\x44\x45LETED\x10\x06*a\n\x08LogLevel\x12\x15\n\x11NOT_SET_LOG_LEVEL\x10\x00\x12\t\n\x05TRACE\x10\x01\x12\t\n\x05\x44\x45\x42UG\x10\x02\x12\x08\n\x04INFO\x10\x03\x12\x08\n\x04WARN\x10\x05\x12\t\n\x05\x45RROR\x10\x06\x12\t\n\x05\x46\x41TAL\x10\t*G\n\tOnFailure\x12\x0b\n\x07NOT_SET\x10\x00\x12\x10\n\x0cLOG_AND_PASS\x10\x01\x12\x10\n\x0cLOG_AND_FAIL\x10\x02\x12\t\n\x05THROW\x10\x03\x42L\n\x13\x63loud.prefab.domainB\x06PrefabZ-github.com/prefab-cloud/prefab-cloud-go/protob\x06proto3"
9
9
 
10
10
  pool = Google::Protobuf::DescriptorPool.generated_pool
11
-
12
- begin
13
- pool.add_serialized_file(descriptor_data)
14
- rescue TypeError
15
- # Compatibility code: will be removed in the next major version.
16
- require 'google/protobuf/descriptor_pb'
17
- parsed = Google::Protobuf::FileDescriptorProto.decode(descriptor_data)
18
- parsed.clear_dependency
19
- serialized = parsed.class.encode(parsed)
20
- file = pool.add_serialized_file(serialized)
21
- warn "Warning: Protobuf detected an import path issue while loading generated file #{__FILE__}"
22
- imports = [
23
- ]
24
- imports.each do |type_name, expected_filename|
25
- import_file = pool.lookup(type_name).file_descriptor
26
- if import_file.name != expected_filename
27
- warn "- #{file.name} imports #{expected_filename}, but that import was loaded as #{import_file.name}"
28
- end
29
- end
30
- warn "Each proto file must use a consistent fully-qualified name."
31
- warn "This will become an error in the next major version."
32
- end
11
+ pool.add_serialized_file(descriptor_data)
33
12
 
34
13
  module PrefabProto
35
14
  ConfigServicePointer = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ConfigServicePointer").msgclass
36
15
  ConfigValue = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.ConfigValue").msgclass
16
+ Json = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Json").msgclass
37
17
  IsoDuration = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.IsoDuration").msgclass
38
18
  Provided = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.Provided").msgclass
39
19
  IntRange = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("prefab.IntRange").msgclass
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: prefab-cloud-ruby 1.7.1 ruby lib
5
+ # stub: prefab-cloud-ruby 1.8.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "prefab-cloud-ruby".freeze
9
- s.version = "1.7.1"
9
+ s.version = "1.8.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Jeff Dwyer".freeze]
14
- s.date = "2024-04-11"
14
+ s.date = "2024-08-22"
15
15
  s.description = "Feature Flags, Live Config, and Dynamic Log Levels as a service".freeze
16
16
  s.email = "jdwyer@prefab.cloud".freeze
17
17
  s.extra_rdoc_files = [
@@ -74,6 +74,7 @@ Gem::Specification.new do |s|
74
74
  "lib/prefab/prefab.rb",
75
75
  "lib/prefab/rate_limit_cache.rb",
76
76
  "lib/prefab/resolved_config_presenter.rb",
77
+ "lib/prefab/sse_config_client.rb",
77
78
  "lib/prefab/time_helpers.rb",
78
79
  "lib/prefab/weighted_value_resolver.rb",
79
80
  "lib/prefab/yaml_config_parser.rb",
@@ -113,6 +114,7 @@ Gem::Specification.new do |s|
113
114
  "test/test_options.rb",
114
115
  "test/test_prefab.rb",
115
116
  "test/test_rate_limit_cache.rb",
117
+ "test/test_sse_config_client.rb",
116
118
  "test/test_weighted_value_resolver.rb"
117
119
  ]
118
120
  s.homepage = "http://github.com/prefab-cloud/prefab-cloud-ruby".freeze
@@ -1,9 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class IntegrationTest
4
- attr_reader :func, :input, :expected, :data, :expected_data, :aggregator, :endpoint, :test_client
4
+ attr_reader :func, :input, :expected, :data, :expected_data, :aggregator, :endpoint, :test_client, :block_context
5
5
 
6
6
  def initialize(test_data)
7
+ @global_context = test_data['contexts']['global'] if test_data['contexts']
8
+ @block_context = test_data['contexts']['block'] if test_data['contexts']
9
+ @local_context = test_data['contexts']['local'] if test_data['contexts']
10
+
7
11
  @client_overrides = parse_client_overrides(test_data['client_overrides'])
8
12
  @func = parse_function(test_data['function'])
9
13
  @input = parse_input(test_data['input'])
@@ -16,6 +20,10 @@ class IntegrationTest
16
20
  @test_client = capture_telemetry(base_client)
17
21
  end
18
22
 
23
+ def teardown
24
+ test_client.stop
25
+ end
26
+
19
27
  def test_type
20
28
  if @data
21
29
  :telemetry
@@ -49,7 +57,11 @@ class IntegrationTest
49
57
  def parse_client_overrides(overrides)
50
58
  Hash[
51
59
  (overrides || {}).map do |(k, v)|
52
- [k.to_sym, v]
60
+ if k.to_s == "prefab_api_url"
61
+ [:sources, [v]]
62
+ else
63
+ [k.to_sym, v]
64
+ end
53
65
  end
54
66
  ]
55
67
  end
@@ -74,14 +86,16 @@ class IntegrationTest
74
86
 
75
87
  def parse_config_input(input)
76
88
  if !input['default'].nil?
77
- [input['key'], input['default']]
89
+ [input['key'], input['default'], @local_context]
90
+ elsif @local_context
91
+ [input['key'], Prefab::NO_DEFAULT_PROVIDED, @local_context]
78
92
  else
79
93
  [input['key']]
80
94
  end
81
95
  end
82
96
 
83
97
  def parse_ff_input(input)
84
- [input['flag'], input['default'], input['context']]
98
+ [input['flag'], input['default'], @local_context]
85
99
  end
86
100
 
87
101
  def parse_expected(expected)
@@ -121,16 +135,22 @@ class IntegrationTest
121
135
  prefab_envs: ['unit_tests'],
122
136
  prefab_datasources: Prefab::Options::DATASOURCES::ALL,
123
137
  api_key: ENV['PREFAB_INTEGRATION_TEST_API_KEY'],
124
- prefab_api_url: 'https://api.staging-prefab.cloud',
138
+ sources: [
139
+ 'https://belt.staging-prefab.cloud',
140
+ 'https://suspenders.staging-prefab.cloud',
141
+ ],
142
+ global_context: @global_context || {},
125
143
  }.merge(@client_overrides))
126
144
  end
127
145
 
128
146
  def capture_telemetry(client)
147
+ super_method = client.method(:post)
148
+
129
149
  client.define_singleton_method(:post) do |url, data|
130
150
  client.instance_variable_set(:@last_data_sent, data)
131
151
  client.instance_variable_set(:@last_post_endpoint, url)
132
152
 
133
- result = super(url, data)
153
+ result = super_method.call(url, data)
134
154
 
135
155
  client.instance_variable_set(:@last_post_result, result)
136
156
 
@@ -2,16 +2,12 @@
2
2
 
3
3
  module IntegrationTestHelpers
4
4
  SUBMODULE_PATH = 'test/prefab-cloud-integration-test-data'
5
- RAISE_IF_NO_TESTS_FOUND = ENV['PREFAB_INTEGRATION_TEST_RAISE'] == 'true'
6
5
 
7
6
  def self.find_integration_tests
8
7
  files = find_test_files
9
8
 
10
9
  if files.none?
11
- message = "No integration tests found"
12
- raise message if RAISE_IF_NO_TESTS_FOUND
13
-
14
- puts message
10
+ raise "No integration tests found"
15
11
  end
16
12
 
17
13
  files
@@ -44,7 +40,7 @@ module IntegrationTestHelpers
44
40
  end
45
41
  end
46
42
 
47
- [aggregator, ->(data) { data.loggers }, expected_loggers.values]
43
+ [aggregator, ->(data) { data.events[0].loggers.loggers }, expected_loggers.values]
48
44
  when "context_shape"
49
45
  aggregator = it.test_client.context_shape_aggregator
50
46
 
@@ -59,13 +55,13 @@ module IntegrationTestHelpers
59
55
  )
60
56
  end
61
57
 
62
- [aggregator, ->(data) { data.shapes }, expected]
58
+ [aggregator, ->(data) { data.events[0].context_shapes.shapes }, expected]
63
59
  when "evaluation_summary"
64
60
  aggregator = it.test_client.evaluation_summary_aggregator
65
61
 
66
62
  aggregator.instance_variable_set("@data", Concurrent::Hash.new)
67
63
 
68
- it.data.each do |key|
64
+ it.data["keys"].each do |key|
69
65
  it.test_client.get(key)
70
66
  end
71
67
 
@@ -129,7 +125,7 @@ module IntegrationTestHelpers
129
125
  end
130
126
  end
131
127
 
132
- def self.with_parent_context_maybe(context, &block)
128
+ def self.with_block_context_maybe(context, &block)
133
129
  if context
134
130
  Prefab::Context.with_context(context, &block)
135
131
  else
@@ -47,11 +47,14 @@ module CommonHelpers
47
47
  ENV[key] = old_value
48
48
  end
49
49
 
50
+ EFFECTIVELY_NEVER = 99_999 # we sync manually
51
+
50
52
  DEFAULT_NEW_CLIENT_OPTIONS = {
51
53
  prefab_config_override_dir: 'none',
52
54
  prefab_config_classpath_dir: 'test',
53
55
  prefab_envs: ['unit_tests'],
54
- prefab_datasources: Prefab::Options::DATASOURCES::LOCAL_ONLY
56
+ prefab_datasources: Prefab::Options::DATASOURCES::LOCAL_ONLY,
57
+ collect_sync_interval: EFFECTIVELY_NEVER,
55
58
  }.freeze
56
59
 
57
60
  def new_client(overrides = {})
@@ -65,6 +65,12 @@ class TestConfigValueUnwrapper < Minitest::Test
65
65
  assert_equal 390605 ,unwrap(config_value, CONFIG, EMPTY_CONTEXT).in_seconds
66
66
  end
67
67
 
68
+ def test_unwrapping_json
69
+ json = PrefabProto::Json.new(json: '{"a": 1, "b": "c"}')
70
+ config_value = PrefabProto::ConfigValue.new(json: json)
71
+ assert_equal({"a" => 1, "b" => "c"}, unwrap(config_value, CONFIG, EMPTY_CONTEXT))
72
+ end
73
+
68
74
  def test_unwrapping_weighted_values
69
75
  # single value
70
76
  config_value = PrefabProto::ConfigValue.new(weighted_values: weighted_values([['abc', 1]]))
@@ -36,7 +36,7 @@ class TestContextShape < Minitest::Test
36
36
 
37
37
  # If this test fails, it means that we've added a new type to the ConfigValue
38
38
  def test_mapping_is_exhaustive
39
- unsupported = [:bytes, :limit_definition, :log_level, :weighted_values, :int_range, :provided, :duration]
39
+ unsupported = [:bytes, :limit_definition, :log_level, :weighted_values, :int_range, :provided, :duration, :json]
40
40
  type_fields = PrefabProto::ConfigValue.descriptor.lookup_oneof("type").entries
41
41
  supported = type_fields.entries.reject do |entry|
42
42
  unsupported.include?(entry.name.to_sym)
@@ -98,30 +98,36 @@ class TestContextShapeAggregator < Minitest::Test
98
98
 
99
99
  assert_equal [
100
100
  [
101
- '/api/v1/context-shapes',
102
- PrefabProto::ContextShapes.new(shapes: [
103
- PrefabProto::ContextShape.new(
104
- name: 'user', field_types: {
105
- 'age' => 4, 'dob' => 2, 'email' => 2, 'name' => 2
106
- }
107
- ),
108
- PrefabProto::ContextShape.new(
109
- name: 'subscription', field_types: {
110
- 'plan' => 2, 'free' => 5, 'trial' => 5
111
- }
112
- ),
113
- PrefabProto::ContextShape.new(
114
- name: 'device', field_types: {
115
- 'version' => 1, 'os' => 2, 'name' => 2
116
- }
117
- )
118
- ])
101
+ '/api/v1/telemetry',
102
+ PrefabProto::TelemetryEvents.new(
103
+ instance_hash: client.instance_hash,
104
+ events: [
105
+ PrefabProto::TelemetryEvent.new(context_shapes:
106
+
107
+ PrefabProto::ContextShapes.new(shapes: [
108
+ PrefabProto::ContextShape.new(
109
+ name: 'user', field_types: {
110
+ 'age' => 4, 'dob' => 2, 'email' => 2, 'name' => 2
111
+ }
112
+ ),
113
+ PrefabProto::ContextShape.new(
114
+ name: 'subscription', field_types: {
115
+ 'plan' => 2, 'free' => 5, 'trial' => 5
116
+ }
117
+ ),
118
+ PrefabProto::ContextShape.new(
119
+ name: 'device', field_types: {
120
+ 'version' => 1, 'os' => 2, 'name' => 2
121
+ }
122
+ )
123
+ ]))
124
+ ]
125
+ )
119
126
  ]
120
127
  ], requests
121
128
 
122
-
123
129
  assert_logged [
124
- "No success loading checkpoints",
130
+ 'No success loading checkpoints',
125
131
  "Couldn't Initialize In 0. Key some.key. Returning what we have"
126
132
  ]
127
133
  end
@@ -4,8 +4,6 @@ require 'test_helper'
4
4
  require 'timecop'
5
5
 
6
6
  class TestExampleContextsAggregator < Minitest::Test
7
- EFFECTIVELY_NEVER = 99_999 # we sync manually
8
-
9
7
  def test_record
10
8
  aggregator = Prefab::ExampleContextsAggregator.new(client: MockBaseClient.new, max_contexts: 2,
11
9
  sync_interval: EFFECTIVELY_NEVER)
@@ -8,15 +8,22 @@ require 'yaml'
8
8
  class TestIntegration < Minitest::Test
9
9
  IntegrationTestHelpers.find_integration_tests.map do |test_file|
10
10
  tests = YAML.load(File.read(test_file))['tests']
11
+ test_names = []
11
12
 
12
13
  tests.each do |test|
13
- parent_context = test['context']
14
-
15
14
  test['cases'].each do |test_case|
16
- define_method(:"test_#{test['name']}_#{test_case['name']}") do
15
+ new_name = "test_#{test['name']}_#{test_case['name']}"
16
+
17
+ if test_names.include?(new_name)
18
+ raise "Duplicate test name: #{new_name}"
19
+ end
20
+
21
+ test_names << new_name
22
+
23
+ define_method(:"#{new_name}") do
17
24
  it = IntegrationTest.new(test_case)
18
25
 
19
- IntegrationTestHelpers.with_parent_context_maybe(parent_context) do
26
+ IntegrationTestHelpers.with_block_context_maybe(it.block_context) do
20
27
  case it.test_type
21
28
  when :raise
22
29
  err = assert_raises(it.expected[:error]) do
@@ -40,7 +47,7 @@ class TestIntegration < Minitest::Test
40
47
 
41
48
  wait_for -> { it.last_post_result&.status == 200 }
42
49
 
43
- assert it.endpoint == it.last_post_endpoint
50
+ assert_equal "/api/v1/telemetry", it.last_post_endpoint
44
51
 
45
52
  actual = get_actual_data[it.last_data_sent]
46
53
 
@@ -58,6 +65,8 @@ class TestIntegration < Minitest::Test
58
65
  "Prefab::ConfigClient -- Couldn't Initialize In 0.01. Key any-key. Returning what we have"
59
66
  ]
60
67
  end
68
+ ensure
69
+ it.teardown
61
70
  end
62
71
  end
63
72
  end
@@ -32,15 +32,27 @@ class TestLogPathAggregator < Minitest::Test
32
32
  client.log_path_aggregator.send(:sync)
33
33
  end
34
34
 
35
- assert_equal '/api/v1/known-loggers', requests[0][0]
36
- sent_logger = requests[0][1]
37
- assert_equal 'this.is.a.namespace', sent_logger.namespace
38
- assert_equal Prefab::TimeHelpers.now_in_ms, sent_logger.start_at
39
- assert_equal Prefab::TimeHelpers.now_in_ms, sent_logger.end_at
40
- assert_equal client.instance_hash, sent_logger.instance_hash
41
- assert_includes sent_logger.loggers,
42
- PrefabProto::Logger.new(logger_name: 'test.test_log_path_aggregator.test_sync', infos: 2,
43
- errors: 3)
35
+ assert_equal [
36
+ [
37
+ '/api/v1/telemetry',
38
+ PrefabProto::TelemetryEvents.new(
39
+ instance_hash: client.instance_hash,
40
+ events: [
41
+ PrefabProto::TelemetryEvent.new(loggers:
42
+
43
+ PrefabProto::LoggersTelemetryEvent.new(loggers: [
44
+ PrefabProto::Logger.new(
45
+ logger_name: 'test.test_log_path_aggregator.test_sync',
46
+ infos: 2,
47
+ errors: 3
48
+ )
49
+ ],
50
+ start_at: Prefab::TimeHelpers.now_in_ms,
51
+ end_at: Prefab::TimeHelpers.now_in_ms,))
52
+ ]
53
+ )
54
+ ]
55
+ ], requests
44
56
  end
45
57
  end
46
58
 
data/test/test_options.rb CHANGED
@@ -5,18 +5,31 @@ require 'test_helper'
5
5
  class TestOptions < Minitest::Test
6
6
  API_KEY = 'abcdefg'
7
7
 
8
- def test_prefab_api_url
9
- assert_equal 'https://api.prefab.cloud', Prefab::Options.new.prefab_api_url
8
+ def test_api_override_env_var
9
+ assert_equal Prefab::Options::DEFAULT_SOURCES, Prefab::Options.new.sources
10
10
 
11
- with_env 'PREFAB_API_URL', 'https://api.prefab.cloud' do
12
- assert_equal 'https://api.prefab.cloud', Prefab::Options.new.prefab_api_url
11
+ # blank doesn't take effect
12
+ with_env('PREFAB_API_URL_OVERRIDE', '') do
13
+ assert_equal Prefab::Options::DEFAULT_SOURCES, Prefab::Options.new.sources
13
14
  end
14
15
 
15
- with_env 'PREFAB_API_URL', 'https://api.prefab.cloud/' do
16
- assert_equal 'https://api.prefab.cloud', Prefab::Options.new.prefab_api_url
16
+ # non-blank does take effect
17
+ with_env('PREFAB_API_URL_OVERRIDE', 'https://override.example.com') do
18
+ assert_equal ["https://override.example.com"], Prefab::Options.new.sources
17
19
  end
18
20
  end
19
21
 
22
+ def test_overriding_sources
23
+ assert_equal Prefab::Options::DEFAULT_SOURCES, Prefab::Options.new.sources
24
+
25
+ # a plain string ends up wrapped in an array
26
+ source = 'https://example.com'
27
+ assert_equal [source], Prefab::Options.new(sources: source).sources
28
+
29
+ sources = ['https://example.com', 'https://example2.com']
30
+ assert_equal sources, Prefab::Options.new(sources: sources).sources
31
+ end
32
+
20
33
  def test_works_with_named_arguments
21
34
  assert_equal API_KEY, Prefab::Options.new(api_key: API_KEY).api_key
22
35
  end
@@ -0,0 +1,65 @@
1
+ require 'test_helper'
2
+
3
+ class TestSSEConfigClient < Minitest::Test
4
+ def test_client
5
+ sources = [
6
+ "https://api.staging-prefab.cloud/",
7
+ ]
8
+
9
+ options = Prefab::Options.new(sources: sources, api_key: ENV['PREFAB_INTEGRATION_TEST_API_KEY'])
10
+
11
+ config_loader = OpenStruct.new(highwater_mark: 4)
12
+
13
+ client = Prefab::SSEConfigClient.new(options, config_loader)
14
+
15
+ assert_equal 4, client.headers['x-prefab-start-at-id']
16
+
17
+ result = nil
18
+
19
+ # fake our load_configs block
20
+ client.start do |c, source|
21
+ result = c
22
+ assert_equal :sse, source
23
+ end
24
+
25
+ wait_for -> { !result.nil? }
26
+
27
+ assert result.configs.size > 30
28
+ ensure
29
+ client.close
30
+ end
31
+
32
+ def test_failing_over
33
+ sources = [
34
+ "https://does.not.exist.staging-prefab.cloud/",
35
+ "https://api.staging-prefab.cloud/",
36
+ ]
37
+
38
+ options = Prefab::Options.new(sources: sources, api_key: ENV['PREFAB_INTEGRATION_TEST_API_KEY'])
39
+
40
+ config_loader = OpenStruct.new(highwater_mark: 4)
41
+
42
+ client = Prefab::SSEConfigClient.new(options, config_loader)
43
+
44
+ assert_equal 4, client.headers['x-prefab-start-at-id']
45
+
46
+ result = nil
47
+
48
+ # fake our load_configs block
49
+ client.start do |c, source|
50
+ result = c
51
+ assert_equal :sse, source
52
+ end
53
+
54
+ wait_for -> { !result.nil? }, max_wait: 10
55
+
56
+ assert result.configs.size > 30
57
+ ensure
58
+ client.close
59
+
60
+ assert_logged [
61
+ /failed to connect: .*https:\/\/does.not.exist/,
62
+ /HTTP::ConnectionError/,
63
+ ]
64
+ end
65
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prefab-cloud-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.1
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Dwyer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-11 00:00:00.000000000 Z
11
+ date: 2024-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -261,6 +261,7 @@ files:
261
261
  - lib/prefab/prefab.rb
262
262
  - lib/prefab/rate_limit_cache.rb
263
263
  - lib/prefab/resolved_config_presenter.rb
264
+ - lib/prefab/sse_config_client.rb
264
265
  - lib/prefab/time_helpers.rb
265
266
  - lib/prefab/weighted_value_resolver.rb
266
267
  - lib/prefab/yaml_config_parser.rb
@@ -300,6 +301,7 @@ files:
300
301
  - test/test_options.rb
301
302
  - test/test_prefab.rb
302
303
  - test/test_rate_limit_cache.rb
304
+ - test/test_sse_config_client.rb
303
305
  - test/test_weighted_value_resolver.rb
304
306
  homepage: http://github.com/prefab-cloud/prefab-cloud-ruby
305
307
  licenses: