promoted-ruby-client 0.1.5 → 0.1.9

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: 6638e3f3f180e08d693f00d9d53caae30cfc737b2023adf0d181c18c1e379369
4
- data.tar.gz: 429c6c2cfc5022ea9f38913cbc0e4b7d218787f817152661f2624d8265fd1f8b
3
+ metadata.gz: efa5db6f158b8ab87cb8d17020d34e2d797025ea6b2b08ee032eb4be0f9ac715
4
+ data.tar.gz: 957e394b3e61cdfc55b68650392a158a492b0d5904df1bd88e17c9378078161b
5
5
  SHA512:
6
- metadata.gz: 9e9e040d1c232767af0004c92c7b3a79277b7ac0e5a3c45509c46bf869a6a51ed7b5ad4273c68c03c86833482607a2b63da8c43f819f73e069ca6a3caf24ddd3
7
- data.tar.gz: 973bbfd858e00e5f81a42f221c5d2a90c8c2fb3bec93e5b1d8f38ca58c42c47382aa4ed777852ec3bee51483ff211b5da9041a075e285b738107be5f8c08567d
6
+ metadata.gz: a30a50a35881680fda99cb355d7469e1e805f5199db86f32713e3f803c68113e8932ae2458f3359c78f323e6c0914a974cf1579967a8a8760b7d48b0064dade9
7
+ data.tar.gz: fa2dde1f6bc78733f3db6fb8a37e19b8b9a00d3531d1508fc3fce3045f87360f5047086f6446906f8b9aa56dc09b2d217d076ea1c242210d098745aa2eb400da
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- promoted-ruby-client (0.1.5)
4
+ promoted-ruby-client (0.1.9)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -28,10 +28,10 @@ This client will suffice for building log requests. To send actually send traffi
28
28
 
29
29
  ```rb
30
30
  client = Promoted::Ruby::Client::PromotedClient.new({
31
- :metrics_endpoint = "https://<get this from Promoted>",
32
- :delivery_endpoint = "https://<get this from Promoted>",
33
- :metrics_api_key = "<get this from Promoted>",
34
- :delivery_api_key = "<get this from Promoted>"
31
+ :metrics_endpoint => "https://<get this from Promoted>",
32
+ :delivery_endpoint => "https://<get this from Promoted>",
33
+ :metrics_api_key => "<get this from Promoted>",
34
+ :delivery_api_key => "<get this from Promoted>"
35
35
  })
36
36
  ```
37
37
 
@@ -88,7 +88,7 @@ Field Name | Type | Optional? | Description
88
88
  ---------- | ---- | --------- | -----------
89
89
  ```:user_info``` | UserInfo | Yes | The user info structure.
90
90
  ```:insertion_id``` | String | Yes | Generated by the SDK (*do not set*)
91
- ```:request_id``` | String | Yes | Generated by the SDK (*do not set*)
91
+ ```:request_id``` | String | Yes | Generated by the SDK when needed (*do not set*)
92
92
  ```:content_id``` | String | No | Identifier for the content to be shown, must be set.
93
93
  ```:properties``` | Properties | Yes | Any additional custom properties to associate. For v1 integrations, it is fine not to fill in all the properties.
94
94
 
@@ -101,7 +101,7 @@ A request for content insertions.
101
101
  Field Name | Type | Optional? | Description
102
102
  ---------- | ---- | --------- | -----------
103
103
  ```:user_info``` | UserInfo | Yes | The user info structure.
104
- ```:request_id``` | String | Yes | Generated by the SDK (*do not set*)
104
+ ```:request_id``` | String | Yes | Generated by the SDK when needed (*do not set*)
105
105
  ```:use_case``` | String | Yes | One of the use case values, i.e. 'FEED' (see [constants.rb](https://github.com/promotedai/promoted-ruby-client/blob/main/lib/promoted/ruby/client/constants.rb)).
106
106
  ```:properties``` | Properties | Yes | Any additional custom properties to associate.
107
107
  ```:paging``` | Paging | Yes | Paging parameters (see TODO)
data/dev.md CHANGED
@@ -1,9 +1,8 @@
1
-
2
- ## Deploy
1
+ # Deploy
3
2
 
4
3
  1. Update version number.
5
4
  2. Get credentials for deployment from 1password.
6
5
  3. Modify `promoted-ruby-client.gemspec`'s push block.
7
6
  4. Run `gem build promoted-ruby-client.gemspec` to generate `gem`.
8
- 5. Run (using new output) `gem push promoted-ruby-client-0.1.5.gem`
7
+ 5. Run (using new output) `gem push promoted-ruby-client-0.1.9.gem`
9
8
  6. Update README with new version.
@@ -19,8 +19,16 @@ module Promoted
19
19
  class Error < StandardError; end
20
20
 
21
21
  attr_reader :perform_checks, :default_only_log, :delivery_timeout_millis, :metrics_timeout_millis, :should_apply_treatment_func,
22
- :default_request_headers, :http_client
22
+ :default_request_headers, :http_client, :logger, :shadow_traffic_delivery_percent, :async_shadow_traffic
23
+
24
+ attr_accessor :request_logging_on, :enabled
23
25
 
26
+ ##
27
+ # Whether or not the client is currently enabled for execution.
28
+ def enabled?
29
+ @enabled
30
+ end
31
+
24
32
  ##
25
33
  # A common compact method implementation.
26
34
  def self.copy_and_remove_properties
@@ -39,7 +47,8 @@ module Promoted
39
47
  @perform_checks = params[:perform_checks]
40
48
  end
41
49
 
42
- @logger = params[:logger] # Example: Logger.new(STDERR, :progname => "promotedai")
50
+ @logger = params[:logger] # Example: Logger.new(STDERR, :progname => "promotedai")
51
+ @request_logging_on = params[:request_logging_on] || false
43
52
 
44
53
  @default_request_headers = params[:default_request_headers] || {}
45
54
  @metrics_api_key = params[:metrics_api_key] || ''
@@ -52,6 +61,7 @@ module Promoted
52
61
  raise ArgumentError.new("Invalid shadow_traffic_delivery_percent, must be between 0 and 1") if @shadow_traffic_delivery_percent < 0 || @shadow_traffic_delivery_percent > 1.0
53
62
 
54
63
  @sampler = Sampler.new
64
+ @pager = Pager.new
55
65
 
56
66
  # HTTP Client creation
57
67
  @delivery_endpoint = params[:delivery_endpoint] || DEFAULT_DELIVERY_ENDPOINT
@@ -66,21 +76,36 @@ module Promoted
66
76
  @http_client = FaradayHTTPClient.new
67
77
  @validator = Promoted::Ruby::Client::Validator.new
68
78
 
69
- # Thread pool to process delivery of shadow traffic. Will silently drop excess requests beyond the queue
70
- # size, and silently eat errors on the background threads.
71
- @pool = Concurrent::ThreadPoolExecutor.new(
72
- min_threads: 0,
73
- max_threads: 10,
74
- max_queue: 100,
75
- fallback_policy: :discard
76
- )
79
+ @async_shadow_traffic = true
80
+ if params[:async_shadow_traffic] != nil
81
+ @async_shadow_traffic = params[:async_shadow_traffic] || false
82
+ end
83
+
84
+ @pool = nil
85
+ if @async_shadow_traffic
86
+ # Thread pool to process delivery of shadow traffic. Will silently drop excess requests beyond the queue
87
+ # size, and silently eat errors on the background threads.
88
+ @pool = Concurrent::ThreadPoolExecutor.new(
89
+ min_threads: 0,
90
+ max_threads: 10,
91
+ max_queue: 100,
92
+ fallback_policy: :discard
93
+ )
94
+ end
95
+
96
+ @enabled = true
97
+ if params[:enabled] != nil
98
+ @enabled = params[:enabled] || false
99
+ end
77
100
  end
78
101
 
79
102
  ##
80
103
  # Politely shut down a Promoted client.
81
104
  def close
82
- @pool.shutdown
83
- @pool.wait_for_termination
105
+ if @pool
106
+ @pool.shutdown
107
+ @pool.wait_for_termination
108
+ end
84
109
  end
85
110
 
86
111
  ##
@@ -88,19 +113,34 @@ module Promoted
88
113
  def deliver args, headers={}
89
114
  args = Promoted::Ruby::Client::Util.translate_args(args)
90
115
 
116
+ # Respect the enabled state
117
+ if !@enabled
118
+ return {
119
+ insertion: @pager.apply_paging(args[:full_insertion], Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], args[:request][:paging])
120
+ # No log request returned when disabled
121
+ }
122
+ end
123
+
91
124
  delivery_request_builder = RequestBuilder.new
92
125
  delivery_request_builder.set_request_params(args)
93
126
 
94
127
  perform_common_checks!(args) if @perform_checks
95
128
 
96
- pre_delivery_fillin_fields delivery_request_builder
129
+ delivery_request_builder.ensure_client_timestamp
97
130
 
98
131
  response_insertions = []
99
132
  cohort_membership_to_log = nil
100
- insertions_from_promoted = false
133
+ insertions_from_delivery = false
101
134
 
102
135
  only_log = delivery_request_builder.only_log != nil ? delivery_request_builder.only_log : @default_only_log
103
136
  deliver_err = false
137
+
138
+ if !@pager.validate_paging(delivery_request_builder.full_insertion, delivery_request_builder.request[:paging])
139
+ # Invalid input, log and do SDK-side delivery.
140
+ @logger.warn("Invalid paging parameters") if @logger
141
+ only_log = true
142
+ end
143
+
104
144
  if !only_log
105
145
  cohort_membership_to_log = delivery_request_builder.new_cohort_membership_to_log
106
146
 
@@ -117,22 +157,16 @@ module Promoted
117
157
  @logger.error("Error calling delivery: " + err.message) if @logger
118
158
  end
119
159
 
120
- insertions_from_promoted = (response != nil && !deliver_err);
160
+ insertions_from_delivery = (response != nil && !deliver_err);
121
161
  response_insertions = delivery_request_builder.fill_details_from_response(
122
- response ? response[:insertion] : nil)
162
+ response ? response[:insertion] : [])
123
163
  end
124
164
  end
125
165
 
126
166
  request_to_log = nil
127
- if !insertions_from_promoted then
167
+ if !insertions_from_delivery then
128
168
  request_to_log = delivery_request_builder.request
129
- size = delivery_request_builder.request.dig(:paging, :size)
130
- response_insertions = size != nil ? delivery_request_builder.full_insertion[0..size] : delivery_request_builder.full_insertion
131
- end
132
-
133
- if request_to_log
134
- request_to_log[:request_id] = SecureRandom.uuid if not request_to_log[:request_id]
135
- add_missing_ids_on_insertions! request_to_log, response_insertions
169
+ response_insertions = @pager.apply_paging(delivery_request_builder.full_insertion, Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], delivery_request_builder.request[:paging])
136
170
  end
137
171
 
138
172
  log_req = nil
@@ -150,14 +184,12 @@ module Promoted
150
184
  log_request_builder.platform_id = delivery_request_builder.platform_id
151
185
  log_request_builder.timing = delivery_request_builder.timing
152
186
  log_request_builder.user_info = delivery_request_builder.user_info
153
- pre_delivery_fillin_fields log_request_builder
154
-
155
187
 
156
188
  # On a successful delivery request, we don't log the insertions
157
189
  # or the request since they are logged on the server-side.
158
190
  log_req = log_request_builder.log_request_params(
159
- include_insertions: !insertions_from_promoted,
160
- include_request: !insertions_from_promoted)
191
+ include_insertions: !insertions_from_delivery,
192
+ include_request: !insertions_from_delivery)
161
193
  end
162
194
 
163
195
  client_response = {
@@ -173,6 +205,12 @@ module Promoted
173
205
  def prepare_for_logging args, headers={}
174
206
  args = Promoted::Ruby::Client::Util.translate_args(args)
175
207
 
208
+ if !@enabled
209
+ return {
210
+ insertion: args[:full_insertion]
211
+ }
212
+ end
213
+
176
214
  log_request_builder = RequestBuilder.new
177
215
 
178
216
  # Note: This method expects as JSON (string keys) but internally, RequestBuilder
@@ -188,7 +226,7 @@ module Promoted
188
226
  end
189
227
  end
190
228
 
191
- pre_delivery_fillin_fields log_request_builder
229
+ log_request_builder.ensure_client_timestamp
192
230
 
193
231
  if !shadow_traffic_err && should_send_as_shadow_traffic?
194
232
  deliver_shadow_traffic args, headers
@@ -211,29 +249,38 @@ module Promoted
211
249
  private
212
250
 
213
251
  def send_request payload, endpoint, timeout_millis, api_key, headers={}, send_async=false
252
+ resp = nil
253
+
214
254
  headers["x-api-key"] = api_key
215
255
  use_headers = @default_request_headers.merge headers
216
256
 
217
- if send_async
257
+ if @request_logging_on && @logger
258
+ @logger.info("promotedai") {
259
+ "Sending #{payload.to_json} to #{endpoint}"
260
+ }
261
+ end
262
+
263
+ if send_async && @pool
218
264
  @pool.post do
219
- @http_client.send(endpoint, timeout_millis, payload, use_headers)
265
+ start_time = Time.now.to_i
266
+ begin
267
+ resp = @http_client.send(endpoint, timeout_millis, payload, use_headers)
268
+ rescue Faraday::Error => err
269
+ @logger.warn("Deliver call failed with #{err}") if @logger
270
+ return
271
+ end
272
+ ellapsed_time = Time.now.to_i - start_time
273
+ @logger.info("Deliver call completed in #{ellapsed_time} ms") if @logger
220
274
  end
221
275
  else
222
276
  begin
223
- @http_client.send(endpoint, timeout_millis, payload, use_headers)
277
+ resp = @http_client.send(endpoint, timeout_millis, payload, use_headers)
224
278
  rescue Faraday::Error => err
225
279
  raise EndpointError.new(err)
226
280
  end
227
281
  end
228
- end
229
282
 
230
-
231
- def add_missing_ids_on_insertions! request, insertions
232
- insertions.each do |insertion|
233
- insertion[:insertion_id] = SecureRandom.uuid if not insertion[:insertion_id]
234
- insertion[:session_id] = request[:session_id] if request[:session_id]
235
- insertion[:request_id] = request[:request_id] if request[:request_id]
236
- end
283
+ return resp
237
284
  end
238
285
 
239
286
  def should_send_as_shadow_traffic?
@@ -250,8 +297,12 @@ module Promoted
250
297
  delivery_request_params = delivery_request_builder.delivery_request_params(should_compact: false)
251
298
  delivery_request_params[:client_info][:traffic_type] = Promoted::Ruby::Client::TRAFFIC_TYPE['SHADOW']
252
299
 
253
- # Call Delivery API async (fire and forget)
254
- send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers, true)
300
+ # Call Delivery API and log/ignore errors.
301
+ begin
302
+ send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers, true)
303
+ rescue StandardError => err
304
+ @logger.warn("Shadow traffic call failed with #{err}") if @logger
305
+ end
255
306
  end
256
307
 
257
308
  def perform_common_checks!(req)
@@ -272,14 +323,7 @@ module Promoted
272
323
  return true if !cohort_membership[:arm]
273
324
  return cohort_membership[:arm] != Promoted::Ruby::Client::COHORT_ARM['CONTROL']
274
325
  end
275
- end
276
-
277
- # TODO: This probably just goes better in the RequestBuilder class.
278
- def pre_delivery_fillin_fields(log_request_builder)
279
- if log_request_builder.timing[:client_log_timestamp].nil?
280
- log_request_builder.timing[:client_log_timestamp] = Time.now.to_i
281
- end
282
- end
326
+ end
283
327
  end
284
328
  end
285
329
  end
@@ -287,7 +331,9 @@ end
287
331
 
288
332
  # dependent /libs
289
333
  require "promoted/ruby/client/request_builder"
334
+ require "promoted/ruby/client/pager"
290
335
  require "promoted/ruby/client/sampler"
291
336
  require "promoted/ruby/client/util"
292
337
  require "promoted/ruby/client/validator"
293
- require 'securerandom'
338
+ require 'securerandom'
339
+ require 'time'
@@ -0,0 +1,15 @@
1
+ module Promoted
2
+ module Ruby
3
+ module Client
4
+ class IdGenerator
5
+ def initialize;end
6
+
7
+ def newID
8
+ SecureRandom.uuid
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ require 'securerandom'
@@ -0,0 +1,57 @@
1
+ module Promoted
2
+ module Ruby
3
+ module Client
4
+ class Pager
5
+ def validate_paging (insertions, paging)
6
+ if paging && paging[:offset]
7
+ return paging[:offset] < insertions.length
8
+ end
9
+ return true
10
+ end
11
+
12
+ def apply_paging (insertions, insertion_page_type, paging = nil)
13
+ # This is invalid input, stop it before it goes to the server.
14
+ if !validate_paging(insertions, paging)
15
+ return []
16
+ end
17
+
18
+ if !paging
19
+ paging = {
20
+ :offset => 0,
21
+ :size => insertions.length
22
+ }
23
+ end
24
+
25
+ offset = [0, paging[:offset]].max
26
+
27
+ index = offset
28
+ if insertion_page_type == Promoted::Ruby::Client::INSERTION_PAGING_TYPE['PRE_PAGED']
29
+ # When insertions are pre-paged, we don't use offset to
30
+ # window into the provided insertions, although we do use it when
31
+ # assigning positions.
32
+ index = 0
33
+ end
34
+
35
+ size = paging[:size]
36
+ if size <= 0
37
+ size = insertions.length
38
+ end
39
+
40
+ final_insertion_size = [size, insertions.length].min
41
+ insertion_page = Array.new(final_insertion_size)
42
+ 0.upto(final_insertion_size - 1) {|i|
43
+ insertion = insertions[index]
44
+ if insertion[:position] == nil
45
+ insertion[:position] = offset
46
+ end
47
+ insertion_page[i] = insertion
48
+ index = index + 1
49
+ offset = offset + 1
50
+ }
51
+
52
+ return insertion_page
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -8,7 +8,13 @@ module Promoted
8
8
 
9
9
  attr_accessor :timing, :user_info, :platform_id
10
10
 
11
- def initialize;end
11
+ def initialize args = {}
12
+ if args[:id_generator]
13
+ @id_generator = args[:id_generator]
14
+ else
15
+ @id_generator = IdGenerator.new
16
+ end
17
+ end
12
18
 
13
19
  # Populates request parameters from the given arguments, presumed to be a hash of symbols.
14
20
  def set_request_params args = {}
@@ -21,11 +27,13 @@ module Promoted
21
27
  @view_id = request[:view_id]
22
28
  @use_case = Promoted::Ruby::Client::USE_CASES[request[:use_case]] || Promoted::Ruby::Client::USE_CASES['UNKNOWN_USE_CASE']
23
29
  @full_insertion = args[:full_insertion]
24
- @request_id = SecureRandom.uuid
25
30
  @user_info = request[:user_info] || { :user_id => nil, :log_user_id => nil}
26
31
  @timing = request[:timing] || { :client_log_timestamp => Time.now.to_i }
27
32
  @to_compact_metrics_insertion_func = args[:to_compact_metrics_insertion_func]
28
33
  @to_compact_delivery_insertion_func = args[:to_compact_delivery_insertion_func]
34
+
35
+ # If the user didn't create a client request id, we do it for them.
36
+ request[:client_request_id] = request[:client_request_id] || @id_generator.newID
29
37
  end
30
38
 
31
39
  # Only used in delivery
@@ -48,10 +56,16 @@ module Promoted
48
56
  params = {
49
57
  user_info: user_info,
50
58
  timing: timing,
51
- cohort_membership: @experiment,
52
- client_info: @client_info.merge({ :client_type => Promoted::Ruby::Client::CLIENT_TYPE['PLATFORM_SERVER'] })
59
+ client_info: @client_info.merge({ :client_type => Promoted::Ruby::Client::CLIENT_TYPE['PLATFORM_SERVER'] }),
60
+ platform_id: @platform_id,
61
+ view_id: @view_id,
62
+ session_id: @session_id,
63
+ use_case: @use_case,
64
+ search_query: request[:search_query],
65
+ properties: request[:properties],
66
+ paging: request[:paging],
67
+ client_request_id: request[:client_request_id]
53
68
  }
54
- params[:request] = request
55
69
  params[:insertion] = should_compact ? compact_delivery_insertions : full_insertion
56
70
 
57
71
  params.clean!
@@ -88,8 +102,17 @@ module Promoted
88
102
  cohort_membership: @experiment,
89
103
  client_info: @client_info
90
104
  }
91
- params[:request] = [request] if include_request
92
- params[:insertion] = compact_metrics_insertions if include_insertions
105
+
106
+ # Log request allows for multiple requests but here we only send one.
107
+ if include_request
108
+ request[:request_id] = request[:request_id] || @id_generator.newID
109
+ params[:request] = [request]
110
+ end
111
+
112
+ if include_insertions
113
+ params[:insertion] = compact_metrics_insertions if include_insertions
114
+ add_missing_ids_on_insertions! request, params[:insertion]
115
+ end
93
116
 
94
117
  params.clean!
95
118
  end
@@ -102,6 +125,12 @@ module Promoted
102
125
  end
103
126
  end
104
127
 
128
+ def ensure_client_timestamp
129
+ if timing[:client_log_timestamp].nil?
130
+ timing[:client_log_timestamp] = Time.now.to_i
131
+ end
132
+ end
133
+
105
134
  # TODO: This looks overly complicated.
106
135
  def compact_metrics_insertions
107
136
  @insertion = [] # insertion should be set according to the compact insertion
@@ -120,7 +149,7 @@ module Promoted
120
149
  insertion_obj = Hash[insertion_obj]
121
150
  insertion_obj[:user_info] = user_info
122
151
  insertion_obj[:timing] = timing
123
- insertion_obj[:insertion_id] = SecureRandom.uuid # generate random UUID
152
+ insertion_obj[:insertion_id] = @id_generator.newID
124
153
  insertion_obj[:request_id] = request_id
125
154
  insertion_obj[:position] = offset + index
126
155
  insertion_obj = @to_compact_metrics_insertion_func.call(insertion_obj) if @to_compact_metrics_insertion_func
@@ -131,6 +160,14 @@ module Promoted
131
160
 
132
161
  private
133
162
 
163
+ def add_missing_ids_on_insertions! request, insertions
164
+ insertions.each do |insertion|
165
+ insertion[:insertion_id] = @id_generator.newID if not insertion[:insertion_id]
166
+ insertion[:session_id] = request[:session_id] if request[:session_id]
167
+ insertion[:request_id] = request[:request_id] if request[:request_id]
168
+ end
169
+ end
170
+
134
171
  # A list of the response Insertions. This client expects lists to be truncated
135
172
  # already to request.paging.size. If not truncated, this client will truncate
136
173
  # the list.
@@ -142,6 +179,6 @@ module Promoted
142
179
  end
143
180
  end
144
181
 
145
- require 'securerandom'
146
182
  require "promoted/ruby/client/constants"
147
183
  require "promoted/ruby/client/extensions"
184
+ require "promoted/ruby/client/id_generator"
@@ -1,7 +1,7 @@
1
1
  module Promoted
2
2
  module Ruby
3
3
  module Client
4
- VERSION = "0.1.5"
4
+ VERSION = "0.1.9"
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: promoted-ruby-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - scottmcmaster
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-02 00:00:00.000000000 Z
11
+ date: 2021-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -75,6 +75,8 @@ files:
75
75
  - lib/promoted/ruby/client/errors.rb
76
76
  - lib/promoted/ruby/client/extensions.rb
77
77
  - lib/promoted/ruby/client/faraday_http_client.rb
78
+ - lib/promoted/ruby/client/id_generator.rb
79
+ - lib/promoted/ruby/client/pager.rb
78
80
  - lib/promoted/ruby/client/request_builder.rb
79
81
  - lib/promoted/ruby/client/sampler.rb
80
82
  - lib/promoted/ruby/client/util.rb