supergood 0.1.0 → 0.1.2

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: cb3307099fe394492d12e7f204da26d9ccb0cca6d53eae8ad1a3e7cc65ae599f
4
- data.tar.gz: 9d8b94b82e04ccdb7d0751b52a29381ebbba02aa2bc7c4e088354626600af5ed
3
+ metadata.gz: a0cdb2377e5748a6ed76d61765fe3b15b648f397a97d6c9cdd28b592d68fd323
4
+ data.tar.gz: '099acaa41f71ef93c745960d9ec046b6643f68501fd95d140a1dd7c62eec76d1'
5
5
  SHA512:
6
- metadata.gz: add414866656373dbef5a3c78bcdf6c0220eda4855bf83c4c0b2ae4a9861e7ad8f071ebe4b3ab80244b74f0646f4953c0fcf8f8c0bba6e8af23a1c34c1c7522f
7
- data.tar.gz: dec173ab5aeb5b18e9cac6a4ef15c00f8b523982b9f313e92e18a42f0c2ab15f568cf6e85662d86843e9166c155a8236afa42dc9d96f2fb25a6635508398bad7
6
+ metadata.gz: 2c15df0347deb5fcb0a0fdf04054595f8c4c9ef8b4da4fabc7879d6098fbe9595c507902ed6f7ccab95b47877f139d9121a1ecea885cb5f814ec86942cb37b3b
7
+ data.tar.gz: 97beed9cd863cd1175756b3084601a40f53928c205b3a3583ca04931a88f6a4804041b8506dfd7277f4232ed1bb7bad3a6eaf5494fe847955dff22439e1882c7
@@ -0,0 +1,26 @@
1
+ name: Unit Tests
2
+ env:
3
+ DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
4
+ SUPERGOOD_CLIENT_ID: ${{ secrets.STAGING_SUPERGOOD_CLIENT_ID }}
5
+ SUPERGOOD_CLIENT_SECRET: ${{ secrets.STAGING_SUPERGOOD_CLIENT_SECRET }}
6
+ SUPERGOOD_BASE_URL: 'http://localhost:3000'
7
+ SUPERGOOD_ORGANIZATION_ID: ${{ vars.SUPERGOOD_ORGANIZATION_ID }}
8
+ on:
9
+ push:
10
+ branches:
11
+ - master
12
+ pull_request:
13
+ branches: [master]
14
+ jobs:
15
+ test:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v3
19
+ - name: Set up Ruby
20
+ uses: ruby/setup-ruby@359bebbc29cbe6c87da6bc9ea3bc930432750108
21
+ with:
22
+ ruby-version: '3.1'
23
+ - name: Install dependencies
24
+ run: bundle install
25
+ - name: Run tests
26
+ run: bundle exec rspec spec/client_spec.rb
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.2.1
data/Gemfile.lock CHANGED
@@ -1,8 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- supergood (0.0.12)
5
- faraday (~> 2.7, >= 2.7.4)
4
+ supergood (0.1.1)
6
5
  rudash (~> 4.0, >= 4.0.2)
7
6
 
8
7
  GEM
@@ -92,6 +91,7 @@ DEPENDENCIES
92
91
  base64
93
92
  digest
94
93
  dotenv
94
+ faraday (~> 2.7, >= 2.7.4)
95
95
  http (~> 5.1, >= 5.1.1)
96
96
  httparty (~> 0.21.0)
97
97
  json
data/README.md CHANGED
@@ -1,8 +1,10 @@
1
1
  # Supergood
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/supergood`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Monitor the cost and performance of your external API's with two lines of code.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ Interested in learning more? Check us out at https://supergood.ai or Reach out to alex@supergood.ai .
6
+
7
+ Not built on Ruby? We've got a node client, python client and golang client as well.
6
8
 
7
9
  ## Installation
8
10
 
@@ -22,7 +24,19 @@ Or install it yourself as:
22
24
 
23
25
  ## Usage
24
26
 
25
- TODO: Write usage instructions here
27
+ 1. Head over to https://dashboard.supergood.ai and make an account, make sure to use your work email address!
28
+ 2. Click on the tab labeled "API Keys" and generate a client id and client secret.
29
+ 3. Head back to your code and initialize the Supergood client one of two ways:
30
+
31
+ ```
32
+ require 'supergood'
33
+
34
+ Supergood.init(<client_id>, <client_secret>)
35
+ ```
36
+ OR
37
+
38
+ set `SUPERGOOD_CLIENT_ID` and `SUPERGOOD_CLIENT_SECRET` as environment variables and leave the init function as `Supergood.init`
39
+
26
40
 
27
41
  ## Development
28
42
 
@@ -32,5 +46,5 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
46
 
33
47
  ## Contributing
34
48
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/supergood.
49
+ Bug reports and pull requests are welcome on GitHub at https://github.com/supergoodsystems/supergood-rb.
36
50
 
data/lib/supergood/api.rb CHANGED
@@ -1,13 +1,20 @@
1
- require 'faraday'
2
1
  require 'dotenv'
3
2
 
4
3
  Dotenv.load
5
4
 
6
5
  module Supergood
7
6
  class Api
8
- def initialize(header_options, base_url)
7
+ def initialize(client_id, client_secret, base_url)
9
8
  @base_url = base_url
10
- @header_options = header_options
9
+ @header_options = {
10
+ 'Content-Type' => 'application/json',
11
+ 'Authorization' => 'Basic ' + Base64.encode64(client_id + ':' + client_secret).gsub(/\n/, '')
12
+ }
13
+ @local_only = client_id == LOCAL_CLIENT_ID && client_secret == LOCAL_CLIENT_SECRET
14
+ end
15
+
16
+ def header_options
17
+ @header_options
11
18
  end
12
19
 
13
20
  def log
@@ -18,45 +25,33 @@ module Supergood
18
25
  @log = logger
19
26
  end
20
27
 
21
- def set_event_sink_endpoint(endpoint)
22
- @event_sink_endpoint = endpoint
23
- end
24
-
25
- def set_error_sink_endpoint(endpoint)
26
- @error_sink_endpoint = endpoint
27
- end
28
-
29
28
  def post_events(payload)
30
- conn = Faraday.new(url: @base_url, headers: @header_options)
31
- response = conn.post(@event_sink_endpoint, body = payload.to_json, headers = @header_options)
32
- if response.status == 200
33
- return JSON.parse(response.body, symbolize_names: true)
34
- elsif response.status == 401
35
- raise SupergoodException.new ERRORS[:UNAUTHORIZED]
36
- elsif response.status != 200 && response.status != 201
37
- raise SupergoodException.new ERRORS[:POSTING_EVENTS]
29
+ if @local_only
30
+ @log.debug(payload)
31
+ else
32
+ uri = URI(@base_url + '/api/events')
33
+ response = Net::HTTP.post(uri, payload.to_json, @header_options)
34
+ if response.code == '200'
35
+ return JSON.parse(response.body, symbolize_names: true)
36
+ elsif response.code == '401'
37
+ raise SupergoodException.new ERRORS[:UNAUTHORIZED]
38
+ elsif response.code != '200' && response.code != '201'
39
+ raise SupergoodException.new ERRORS[:POSTING_EVENTS]
40
+ end
38
41
  end
39
42
  end
40
43
 
41
44
  def post_errors(payload)
42
- conn = Faraday.new(url: @base_url, headers: @header_options)
43
- response = conn.post(@error_sink_endpoint, body = payload.to_json, headers = @header_options)
44
- if response.status == 200
45
- return JSON.parse(response.body, symbolize_names: true)
45
+ if @local_only
46
+ @log.debug(payload)
46
47
  else
47
- @log.warn(ERRORS[:POSTING_ERRORS])
48
- end
49
- end
50
-
51
- def fetch_config
52
- conn = Faraday.new(url: @base_url, headers: @header_options)
53
- response = conn.get('/api/config')
54
- if response.status == 200
55
- return JSON.parse(response.body, symbolize_names: true)
56
- elsif response.status == 401
57
- raise SupergoodException.new ERRORS[:UNAUTHORIZED]
58
- elsif response.status != 200 && response.status != 201
59
- raise SupergoodException.new ERRORS[:FETCHING_CONFIG]
48
+ uri = URI(@base_url + '/api/errors')
49
+ response = Net::HTTP.post(uri, payload.to_json, @header_options)
50
+ if response.code == '200'
51
+ return JSON.parse(response.body, symbolize_names: true)
52
+ else
53
+ @log.warn(ERRORS[:POSTING_ERRORS])
54
+ end
60
55
  end
61
56
  end
62
57
  end
@@ -12,11 +12,10 @@ Dotenv.load
12
12
  module Supergood
13
13
 
14
14
  DEFAULT_SUPERGOOD_BASE_URL = 'https://dashboard.supergood.ai'
15
-
16
15
  class << self
17
- def init(supergood_client_id=nil, supergood_client_secret=nil, base_url=nil)
18
- supergood_client_id = supergood_client_id || ENV['SUPERGOOD_CLIENT_ID']
19
- supergood_client_secret = supergood_client_secret || ENV['SUPERGOOD_CLIENT_SECRET']
16
+ def init(config={})
17
+ supergood_client_id = config[:client_id] || ENV['SUPERGOOD_CLIENT_ID']
18
+ supergood_client_secret = config[:client_secret] || ENV['SUPERGOOD_CLIENT_SECRET']
20
19
 
21
20
  if !supergood_client_id
22
21
  raise SupergoodException.new ERRORS[:NO_CLIENT_ID]
@@ -26,27 +25,27 @@ module Supergood
26
25
  raise SupergoodException.new ERRORS[:NO_CLIENT_SECRET]
27
26
  end
28
27
 
29
- @base_url = base_url || ENV['SUPERGOOD_BASE_URL'] || DEFAULT_SUPERGOOD_BASE_URL
30
- header_options = {
31
- 'Content-Type' => 'application/json',
32
- 'Authorization' => 'Basic ' + Base64.encode64(supergood_client_id + ':' + supergood_client_secret).gsub(/\n/, '')
33
- }
28
+ @base_url = ENV['SUPERGOOD_BASE_URL'] || DEFAULT_SUPERGOOD_BASE_URL
29
+ @api = Supergood::Api.new(supergood_client_id, supergood_client_secret, @base_url)
30
+ @config = Supergood::Utils.make_config(config)
34
31
 
35
- @api = Supergood::Api.new(header_options, @base_url)
36
- @config = @api.fetch_config
37
32
  @ignored_domains = @config[:ignoredDomains]
38
33
  @keys_to_hash = @config[:keysToHash]
39
- @logger = Supergood::Logger.new(@api, @config, header_options)
34
+ @logger = Supergood::Logger.new(@api, @config, @api.header_options)
40
35
 
41
- @api.set_error_sink_endpoint(@config[:errorSinkEndpoint])
42
- @api.set_event_sink_endpoint(@config[:eventSinkEndpoint])
43
36
  @api.set_logger(@logger)
44
37
 
45
38
  @request_cache = {}
46
39
  @response_cache = {}
47
40
 
48
41
  @interval_thread = set_interval(@config[:flushInterval]) { flush_cache }
49
- log.debug("Using config %s" % @config.inspect)
42
+
43
+ @http_clients = [
44
+ Supergood::Vendor::NetHTTP,
45
+ Supergood::Vendor::HTTPrb
46
+ ]
47
+
48
+ patch_all()
50
49
  self
51
50
  end
52
51
 
@@ -76,6 +75,7 @@ module Supergood
76
75
  api.post_events(data)
77
76
  rescue => e
78
77
  log.error(data, e, e.message)
78
+ cleanup()
79
79
  ensure
80
80
  @response_cache.clear
81
81
  @request_cache.clear if force
@@ -83,10 +83,27 @@ module Supergood
83
83
 
84
84
  end
85
85
 
86
+ def cleanup()
87
+ @interval_thread.kill
88
+ unpatch_all()
89
+ end
90
+
86
91
  def close(force = true)
87
92
  log.debug('Cleaning up, flushing cache gracefully.')
88
- @interval_thread.kill
89
93
  flush_cache(force)
94
+ cleanup()
95
+ end
96
+
97
+ def patch_all
98
+ @http_clients.each do |client|
99
+ client.patch
100
+ end
101
+ end
102
+
103
+ def unpatch_all
104
+ @http_clients.each do |client|
105
+ client.unpatch
106
+ end
90
107
  end
91
108
 
92
109
  def set_interval(delay)
@@ -98,14 +115,6 @@ module Supergood
98
115
  end
99
116
  end
100
117
 
101
- def self.intercept(*args, &block)
102
- instance.intercept(*args, &block)
103
- end
104
-
105
- def self.instance
106
- @instance ||= Supergood.new
107
- end
108
-
109
118
  def intercept(request)
110
119
  request_id = SecureRandom.uuid
111
120
  requested_at = Time.now
@@ -138,6 +147,7 @@ module Supergood
138
147
  }
139
148
  rescue => e
140
149
  log.error({ request: request }, e, ERRORS[:CACHING_REQUEST])
150
+ cleanup()
141
151
  end
142
152
  end
143
153
 
@@ -159,11 +169,11 @@ module Supergood
159
169
  }), @keys_to_hash)
160
170
  @request_cache.delete(request_id)
161
171
  rescue => e
162
- puts e
163
172
  log.error(
164
173
  { request: request_payload, response: response_payload },
165
174
  e, ERRORS[:CACHING_RESPONSE]
166
175
  )
176
+ cleanup()
167
177
  end
168
178
  end
169
179
 
@@ -4,9 +4,8 @@ ERRORS = {
4
4
  DUMPING_DATA_TO_DISK: 'Error Dumping Data to Disk',
5
5
  POSTING_EVENTS: 'Error Posting Events',
6
6
  POSTING_ERRORS: 'Error Posting Errors',
7
- FETCHING_CONFIG: 'Error Fetching Config',
8
7
  WRITING_TO_DISK: 'Error writing to disk',
9
- TEST_ERROR: 'Test Error for Testing Purposes',
8
+ TEST_ERROR: 'Test Error for Testing Purpos es',
10
9
  UNAUTHORIZED: 'Unauthorized: Invalid Client ID or Secret. Exiting.',
11
10
  NO_CLIENT_ID:
12
11
  'No Client ID Provided, set SUPERGOOD_CLIENT_ID or pass it as an argument',
@@ -14,8 +13,17 @@ ERRORS = {
14
13
  'No Client Secret Provided, set SUPERGOOD_CLIENT_SECRET or pass it as an argument'
15
14
  };
16
15
 
16
+ LOCAL_CLIENT_ID = 'local-client-id';
17
+ LOCAL_CLIENT_SECRET = 'local-client-secret';
18
+
17
19
  DEFAULT_SUPERGOOD_BYTE_LIMIT = 500000
18
20
 
21
+ DEFAULT_CONFIG = {
22
+ keysToHash: [],
23
+ flushInterval: 1000,
24
+ ignoredDomains: []
25
+ }
26
+
19
27
  # GZIP_START_BYTES = b'\x1f\x8b'
20
28
 
21
29
  class SupergoodException < StandardError
@@ -68,5 +68,9 @@ module Supergood
68
68
  def self.request_url(http, request)
69
69
  URI::DEFAULT_PARSER.unescape("http#{"s" if http.use_ssl?}://#{http.address}#{request.path}")
70
70
  end
71
+
72
+ def self.make_config(config)
73
+ return DEFAULT_CONFIG.merge(config)
74
+ end
71
75
  end
72
76
  end
@@ -1,33 +1,59 @@
1
1
  module Supergood
2
2
  module Vendor
3
3
  module HTTPrb
4
- if defined?(HTTP::Client)
5
- HTTP::Client.class_eval {
6
- alias original_perform perform
7
- def perform(original_request_payload, original_options)
8
- request = {
9
- headers: original_request_payload.headers.to_hash,
10
- method: original_request_payload.verb.upcase.to_s,
11
- body: Supergood::Utils.safe_parse_json(original_request_payload.body.source),
12
- url: original_request_payload.uri.to_s,
13
- path: original_request_payload.uri.path,
14
- search: original_request_payload.uri.query,
15
- domain: original_request_payload.uri.host
16
- }
17
- Supergood.intercept(request) do
18
- original_response = original_perform(original_request_payload, original_options)
19
- status, statusText = original_response.status.to_s.split(' ')
20
- {
21
- headers: original_response.headers.to_hash,
22
- status: status,
23
- statusText: statusText,
24
- body: Supergood::Utils.safe_parse_json(original_response),
25
- original_response: original_response
4
+ def self.patch
5
+ if !self.existing_patch?
6
+
7
+ block = lambda do |x|
8
+ alias original_perform perform
9
+ def perform(original_request_payload, original_options)
10
+ request = {
11
+ headers: original_request_payload.headers.to_hash,
12
+ method: original_request_payload.verb.upcase.to_s,
13
+ body: Supergood::Utils.safe_parse_json(original_request_payload.body.source),
14
+ url: original_request_payload.uri.to_s,
15
+ path: original_request_payload.uri.path,
16
+ search: original_request_payload.uri.query,
17
+ domain: original_request_payload.uri.host
26
18
  }
19
+ Supergood.intercept(request) do
20
+ original_response = original_perform(original_request_payload, original_options)
21
+ status, statusText = original_response.status.to_s.split(' ')
22
+ {
23
+ headers: original_response.headers.to_hash,
24
+ status: status,
25
+ statusText: statusText,
26
+ body: Supergood::Utils.safe_parse_json(original_response),
27
+ original_response: original_response
28
+ }
29
+ end
27
30
  end
28
31
  end
29
- }
32
+
33
+ if defined?(HTTP::Client)
34
+ HTTP::Client.class_eval(&block)
35
+ end
36
+
37
+ end
38
+ end
39
+
40
+ def self.unpatch
41
+ if self.existing_patch?
42
+ block = lambda do |x|
43
+ alias perform original_perform
44
+ end
45
+
46
+ if defined?(HTTP::Client)
47
+ HTTP::Client.class_eval(&block)
48
+ HTTP::Client.undef_method :original_perform
49
+ end
50
+ end
30
51
  end
52
+
53
+ def self.existing_patch?
54
+ defined?(HTTP::Client) && HTTP::Client.method_defined?(:original_perform)
55
+ end
56
+
31
57
  end
32
58
  end
33
59
  end
@@ -5,41 +5,66 @@ require 'uri'
5
5
  module Supergood
6
6
  module Vendor
7
7
  module NetHTTP
8
- block = lambda do |x|
9
- alias original_request_method request
10
- def request(original_request_payload, body = nil, &block)
11
- http = self;
12
- url = Supergood::Utils.request_url(http, original_request_payload)
13
- uri = URI.parse(url)
14
- request = {
15
- headers: Supergood::Utils.get_header(original_request_payload),
16
- method: original_request_payload.method,
17
- body: original_request_payload.body,
18
- url: url,
19
- path: original_request_payload.path,
20
- search: uri.query,
21
- domain: uri.host,
22
- }
23
- Supergood.intercept(request) do
24
- original_response = original_request_method(original_request_payload, body, &block)
25
- {
26
- headers: Supergood::Utils.get_header(original_response),
27
- status: original_response.code,
28
- statusText: original_response.message,
29
- body: original_response.body,
30
- original_response: original_response
31
- }
8
+ def self.patch
9
+ if !self.existing_patch?
10
+ block = lambda do |x|
11
+ alias original_request_method request
12
+ def request(original_request_payload, body = nil, &block)
13
+ http = self;
14
+ url = Supergood::Utils.request_url(http, original_request_payload)
15
+ uri = URI.parse(url)
16
+ request = {
17
+ headers: Supergood::Utils.get_header(original_request_payload),
18
+ method: original_request_payload.method,
19
+ body: original_request_payload.body,
20
+ url: url,
21
+ path: original_request_payload.path,
22
+ search: uri.query,
23
+ domain: uri.host,
24
+ }
25
+ Supergood.intercept(request) do
26
+ original_response = original_request_method(original_request_payload, body, &block)
27
+ {
28
+ headers: Supergood::Utils.get_header(original_response),
29
+ status: original_response.code,
30
+ statusText: original_response.message,
31
+ body: original_response.body,
32
+ original_response: original_response
33
+ }
34
+ end
35
+ end
32
36
  end
37
+
38
+ if defined?(Net::HTTP)
39
+ Net::HTTP.class_eval(&block)
40
+ elsif defined?(::WebMock)
41
+ WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get("@webMockNetHTTP").class_eval(&block)
42
+ end
43
+
33
44
  end
34
45
  end
35
46
 
36
- if defined?(Net::HTTP)
37
- Net::HTTP.class_eval(&block)
47
+ def self.unpatch
48
+ if self.existing_patch?
49
+ block = lambda do |x|
50
+ alias request original_request_method
51
+ end
52
+
53
+ if defined?(Net::HTTP)
54
+ Net::HTTP.class_eval(&block)
55
+ Net::HTTP.undef_method :original_request_method
56
+ elsif defined?(::WebMock)
57
+ WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get("@webMockNetHTTP").class_eval(&block)
58
+ WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get("@webMockNetHTTP").undef_method :original_request_method
59
+ end
60
+ end
38
61
  end
39
62
 
40
- if defined?(::WebMock)
41
- WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get("@webMockNetHTTP").class_eval(&block)
63
+ def self.existing_patch?
64
+ (defined?(Net::HTTP) && Net::HTTP.method_defined?(:original_request_method)) ||
65
+ (defined?(::Webmock) && WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get("@webMockNetHTTP").method_defined?(:original_request_method))
42
66
  end
67
+
43
68
  end
44
69
  end
45
70
  end
@@ -1,3 +1,3 @@
1
1
  module Supergood
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.1.2'.freeze
3
3
  end
data/supergood.gemspec CHANGED
@@ -19,13 +19,13 @@ Gem::Specification.new do |s|
19
19
  s.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
20
20
 
21
21
  s.add_dependency 'rudash', '~> 4.0', '>= 4.0.2'
22
- s.add_dependency 'faraday', '~> 2.7', '>= 2.7.4'
23
22
 
24
23
  s.add_development_dependency 'rest-client', '~> 2.1'
25
24
  s.add_development_dependency 'httparty', '~> 0.21.0'
26
25
  s.add_development_dependency 'http', '~> 5.1', '>= 5.1.1'
27
26
  s.add_development_dependency 'rspec', '~> 3.12'
28
27
  s.add_development_dependency 'webmock', '~> 3.18', '>= 3.18.1'
28
+ s.add_development_dependency 'faraday', '~> 2.7', '>= 2.7.4'
29
29
 
30
30
  end
31
31
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: supergood
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Klarfeld
@@ -30,26 +30,6 @@ dependencies:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: 4.0.2
33
- - !ruby/object:Gem::Dependency
34
- name: faraday
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: '2.7'
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: 2.7.4
43
- type: :runtime
44
- prerelease: false
45
- version_requirements: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - "~>"
48
- - !ruby/object:Gem::Version
49
- version: '2.7'
50
- - - ">="
51
- - !ruby/object:Gem::Version
52
- version: 2.7.4
53
33
  - !ruby/object:Gem::Dependency
54
34
  name: rest-client
55
35
  requirement: !ruby/object:Gem::Requirement
@@ -132,14 +112,36 @@ dependencies:
132
112
  - - ">="
133
113
  - !ruby/object:Gem::Version
134
114
  version: 3.18.1
115
+ - !ruby/object:Gem::Dependency
116
+ name: faraday
117
+ requirement: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - "~>"
120
+ - !ruby/object:Gem::Version
121
+ version: '2.7'
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 2.7.4
125
+ type: :development
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '2.7'
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 2.7.4
135
135
  description:
136
136
  email: alex@supergood.ai
137
137
  executables: []
138
138
  extensions: []
139
139
  extra_rdoc_files: []
140
140
  files:
141
+ - ".github/workflows/test.yml"
141
142
  - ".gitignore"
142
143
  - ".rspec"
144
+ - ".tool-versions"
143
145
  - ".travis.yml"
144
146
  - ".vscode/settings.json"
145
147
  - Gemfile