promoted-ruby-client 0.1.5 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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