simplyq 0.8.0rc
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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +58 -0
- data/.rubocop_todo.yml +156 -0
- data/.tool-versions +1 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +27 -0
- data/LICENSE.txt +21 -0
- data/README.md +37 -0
- data/Rakefile +12 -0
- data/lib/simplyq/api/application_api.rb +82 -0
- data/lib/simplyq/api/endpoint_api.rb +178 -0
- data/lib/simplyq/api/event_api.rb +140 -0
- data/lib/simplyq/client.rb +304 -0
- data/lib/simplyq/configuration.rb +185 -0
- data/lib/simplyq/errors.rb +96 -0
- data/lib/simplyq/models/application.rb +196 -0
- data/lib/simplyq/models/delivery_attempt.rb +110 -0
- data/lib/simplyq/models/endpoint.rb +226 -0
- data/lib/simplyq/models/event.rb +133 -0
- data/lib/simplyq/models/inbound_event.rb +37 -0
- data/lib/simplyq/models/list.rb +120 -0
- data/lib/simplyq/version.rb +5 -0
- data/lib/simplyq/webhook.rb +102 -0
- data/lib/simplyq.rb +26 -0
- data/sig/simplyq.rbs +4 -0
- data/simplyq.gemspec +40 -0
- metadata +121 -0
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Simplyq
|
4
|
+
module Model
|
5
|
+
class Event
|
6
|
+
attr_accessor :uid
|
7
|
+
|
8
|
+
attr_accessor :event_type
|
9
|
+
|
10
|
+
attr_accessor :topics
|
11
|
+
|
12
|
+
attr_accessor :payload
|
13
|
+
|
14
|
+
attr_accessor :retention_period
|
15
|
+
|
16
|
+
attr_accessor :created_at
|
17
|
+
|
18
|
+
def initialize(attributes = {})
|
19
|
+
self.uid = attributes[:uid] if attributes.key?(:uid)
|
20
|
+
|
21
|
+
self.event_type = attributes[:event_type] if attributes.key?(:event_type)
|
22
|
+
|
23
|
+
self.topics = attributes[:topics] if attributes.key?(:topics)
|
24
|
+
|
25
|
+
self.payload = attributes[:payload] if attributes.key?(:payload)
|
26
|
+
|
27
|
+
self.retention_period = attributes[:retention_period] if attributes.key?(:retention_period)
|
28
|
+
|
29
|
+
self.created_at = attributes[:created_at] if attributes.key?(:created_at)
|
30
|
+
end
|
31
|
+
|
32
|
+
# The model identifier attribute used in list operations
|
33
|
+
#
|
34
|
+
# @return [Symbol]
|
35
|
+
def self.identifier
|
36
|
+
:uid
|
37
|
+
end
|
38
|
+
|
39
|
+
# Serializes the object from a hash
|
40
|
+
#
|
41
|
+
# @param hash [Hash] Hash with the object data
|
42
|
+
# @return [Simplyq::Model::Event]
|
43
|
+
def self.from_hash(hash)
|
44
|
+
return if hash.nil?
|
45
|
+
|
46
|
+
new(hash)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Show invalid properties with the reasons. Usually used together with valid?
|
50
|
+
# @return Array for valid properties with the reasons
|
51
|
+
def validation_errors
|
52
|
+
invalid_properties = []
|
53
|
+
if !@uid.nil? && @uid.to_s.length > 255
|
54
|
+
invalid_properties.push('invalid value for "uid", the character length must be smaller than or equal to 255.')
|
55
|
+
end
|
56
|
+
|
57
|
+
if !@uid.nil? && @uid.to_s.empty?
|
58
|
+
invalid_properties.push('invalid value for "uid", the character length must be great than or equal to 1.')
|
59
|
+
end
|
60
|
+
|
61
|
+
pattern = Regexp.new(/^[a-zA-Z0-9\-_.]+$/)
|
62
|
+
if !@uid.nil? && @uid !~ pattern
|
63
|
+
invalid_properties.push("invalid value for \"uid\", must conform to the pattern #{pattern}.")
|
64
|
+
end
|
65
|
+
|
66
|
+
if !@event_type.nil? && @event_type.to_s.length > 255
|
67
|
+
invalid_properties.push('invalid value for "event_type", the character length must be smaller than or equal to 255.')
|
68
|
+
end
|
69
|
+
|
70
|
+
if !@event_type.nil? && @event_type.to_s.empty?
|
71
|
+
invalid_properties.push('invalid value for "event_type", the character length must be great than or equal to 1.')
|
72
|
+
end
|
73
|
+
|
74
|
+
pattern = Regexp.new(/^[a-zA-Z0-9\-_.]+$/)
|
75
|
+
if !@event_type.nil? && @event_type !~ pattern
|
76
|
+
invalid_properties.push("invalid value for \"event_type\", must conform to the pattern #{pattern}.")
|
77
|
+
end
|
78
|
+
|
79
|
+
if !@retention_period.nil? && @retention_period > 90
|
80
|
+
invalid_properties.push('invalid value for "retention_period", must be smaller than or equal to 90.')
|
81
|
+
end
|
82
|
+
|
83
|
+
invalid_properties
|
84
|
+
end
|
85
|
+
|
86
|
+
# Check if the model is valid
|
87
|
+
# @return true if valid, false otherwise
|
88
|
+
def valid?
|
89
|
+
validation_errors.empty?
|
90
|
+
end
|
91
|
+
|
92
|
+
def [](key)
|
93
|
+
instance_variable_get(:"@#{key}")
|
94
|
+
end
|
95
|
+
|
96
|
+
def ==(other)
|
97
|
+
return false unless other.is_a?(Event)
|
98
|
+
|
99
|
+
uid == other.uid &&
|
100
|
+
event_type == other.event_type &&
|
101
|
+
topics == other.topics &&
|
102
|
+
payload == other.payload &&
|
103
|
+
retention_period == other.retention_period &&
|
104
|
+
created_at == other.created_at
|
105
|
+
end
|
106
|
+
|
107
|
+
def to_h
|
108
|
+
{
|
109
|
+
uid: uid,
|
110
|
+
event_type: event_type,
|
111
|
+
topics: topics,
|
112
|
+
payload: _safe_parse_payload_to_hash(payload),
|
113
|
+
retention_period: retention_period,
|
114
|
+
created_at: created_at
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
def _safe_parse_payload_to_hash(value)
|
119
|
+
return if value.nil?
|
120
|
+
return value if value.is_a?(Hash)
|
121
|
+
return value.to_h if value.respond_to?(:to_h)
|
122
|
+
|
123
|
+
JSON.parse(value)
|
124
|
+
rescue JSON::ParserError
|
125
|
+
value
|
126
|
+
end
|
127
|
+
|
128
|
+
def to_json(*args)
|
129
|
+
to_h.to_json(*args)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Simplyq
|
4
|
+
module Model
|
5
|
+
class InboundEvent
|
6
|
+
attr_accessor :data
|
7
|
+
|
8
|
+
def initialize(data)
|
9
|
+
self.data = data
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.from_hash(hash)
|
13
|
+
return if hash.nil?
|
14
|
+
|
15
|
+
new(hash)
|
16
|
+
end
|
17
|
+
|
18
|
+
def ==(other)
|
19
|
+
return false unless other.is_a?(InboundEvent)
|
20
|
+
|
21
|
+
data == other.data
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_h
|
25
|
+
data
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](key)
|
29
|
+
data[key]
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_json(*args)
|
33
|
+
to_h.to_json(*args)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
module Simplyq
|
6
|
+
module Model
|
7
|
+
class List
|
8
|
+
extend Forwardable
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
attr_accessor :data
|
12
|
+
attr_accessor :has_more
|
13
|
+
|
14
|
+
attr_accessor :data_type
|
15
|
+
attr_accessor :api_method
|
16
|
+
attr_accessor :list_args
|
17
|
+
attr_accessor :filters
|
18
|
+
attr_accessor :api
|
19
|
+
|
20
|
+
def initialize(data_type, attributes = {}, api_method:, api:, filters: {}, list_args: [])
|
21
|
+
self.data = if attributes.key?(:data)
|
22
|
+
attributes[:data].map do |item|
|
23
|
+
if data_type == Hash
|
24
|
+
item
|
25
|
+
else
|
26
|
+
data_type.from_hash(item)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
else
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
|
33
|
+
self.has_more = attributes[:has_more]
|
34
|
+
|
35
|
+
self.data_type = data_type
|
36
|
+
|
37
|
+
self.api_method = api_method
|
38
|
+
|
39
|
+
self.filters = filters
|
40
|
+
|
41
|
+
self.list_args = list_args
|
42
|
+
|
43
|
+
self.api = api
|
44
|
+
end
|
45
|
+
|
46
|
+
def_delegators :data, :size, :length, :count, :empty?,
|
47
|
+
:first, :last, :each_with_index, :each_with_object,
|
48
|
+
:reduce, :inject, :find, :find_index, :index, :rindex
|
49
|
+
|
50
|
+
def [](key)
|
51
|
+
if key.is_a?(Integer)
|
52
|
+
data[key]
|
53
|
+
else
|
54
|
+
instance_variable_get(:"@#{key}")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Iterates through each resource in the page represented by the current
|
59
|
+
# `List`.
|
60
|
+
#
|
61
|
+
# Note that this method will not attempt to fetch the next page when it
|
62
|
+
# reaches the end of the current page.
|
63
|
+
def each(&blk)
|
64
|
+
data.each(&blk)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Iterates through each resource in the page represented by the current
|
68
|
+
# `List`.
|
69
|
+
#
|
70
|
+
# Note that this method will not attempt to fetch the next page when it
|
71
|
+
# reaches the end of the current page.
|
72
|
+
def map(&blk)
|
73
|
+
data.map(&blk)
|
74
|
+
end
|
75
|
+
|
76
|
+
def next_page
|
77
|
+
return nil unless has_more || !empty?
|
78
|
+
|
79
|
+
query_params = filters.dup.tap { |h| h.delete(:ending_before) }
|
80
|
+
query_params[:start_after] = last.send(data_type.identifier)
|
81
|
+
api.send(api_method, *list_args, query_params)
|
82
|
+
end
|
83
|
+
|
84
|
+
def prev_page
|
85
|
+
return nil if empty?
|
86
|
+
|
87
|
+
query_params = filters.dup.tap { |h| h.delete(:start_after) }
|
88
|
+
query_params[:ending_before] = first.send(data_type.identifier)
|
89
|
+
api.send(api_method, *list_args, query_params)
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_h
|
93
|
+
{
|
94
|
+
data: data.map(&:to_h),
|
95
|
+
has_more: has_more
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_json(*args)
|
100
|
+
to_h.to_json(*args)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Serializes the object from a hash
|
104
|
+
#
|
105
|
+
# @param hash [Hash] Hash with the object data
|
106
|
+
# @return [Simplyq::Model::List]
|
107
|
+
def self.from_hash(hash, data_type, api:, filters: {})
|
108
|
+
return if hash.nil?
|
109
|
+
|
110
|
+
new(data_type, hash, api: api, filters: filters)
|
111
|
+
end
|
112
|
+
|
113
|
+
def ==(other)
|
114
|
+
return false unless other.is_a?(List)
|
115
|
+
|
116
|
+
data == other.data && has_more == other.has_more
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "openssl"
|
4
|
+
require "base64"
|
5
|
+
|
6
|
+
module Simplyq
|
7
|
+
module Webhook
|
8
|
+
DEFAULT_TOLERANCE = 300
|
9
|
+
TIMESTAMP_HEADER = "x-simplyq-timestamp"
|
10
|
+
SIGNATURE_HEADER = "x-simplyq-signature"
|
11
|
+
|
12
|
+
# Verify signature of webhook request
|
13
|
+
#
|
14
|
+
# @param payload_body [String] raw payload body
|
15
|
+
# @param signatures [String] request signature header
|
16
|
+
# @param timestamp [String] request timestamp header
|
17
|
+
# @param secret [String] your endpoint secret
|
18
|
+
# @param tolerance [Integer] duration before signature expires
|
19
|
+
# (default: 300 seconds) replay attack protection
|
20
|
+
# @raise [SignatureVerificationError] if signature verification fails
|
21
|
+
#
|
22
|
+
# @return [Boolean] true if signature verification succeeds
|
23
|
+
def self.verify_signature(payload_body, signatures:, timestamp:, secret:, tolerance: DEFAULT_TOLERANCE)
|
24
|
+
Signature.verify_header(payload_body, signatures, timestamp, secret, tolerance: tolerance)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Decerialize and verify signature of payload into an InboundEvent
|
28
|
+
#
|
29
|
+
# @param payload_body [String] raw payload body
|
30
|
+
# @param signatures [String] request signature header
|
31
|
+
# @param timestamp [String] request timestamp header
|
32
|
+
# @param secret [String] your endpoint secret
|
33
|
+
# @param tolerance [Integer] duration before signature expires
|
34
|
+
# (default: 300 seconds) replay attack protection
|
35
|
+
# @raise [SignatureVerificationError] if signature verification fails
|
36
|
+
# @raise [JSON::ParserError] if payload_body is not valid JSON
|
37
|
+
#
|
38
|
+
# @return [Model::InboundEvent]
|
39
|
+
def self.construct_event(payload_body, signatures:, timestamp:, secret:, tolerance: DEFAULT_TOLERANCE)
|
40
|
+
Signature.verify_header(payload_body, signatures, timestamp, secret, tolerance: tolerance)
|
41
|
+
|
42
|
+
Model::InboundEvent.from_hash(JSON.parse(payload_body, symbolize_names: true))
|
43
|
+
end
|
44
|
+
|
45
|
+
module Signature
|
46
|
+
def self.calculate_signature(timestamp, payload, secret)
|
47
|
+
raise ArgumentError, "timestamp should be an instance of Time" unless timestamp.is_a?(Time)
|
48
|
+
raise ArgumentError, "payload should be a string" unless payload.is_a?(String)
|
49
|
+
raise ArgumentError, "secret should be a string" unless secret.is_a?(String)
|
50
|
+
|
51
|
+
sig = OpenSSL::HMAC.digest("SHA256", secret, "#{timestamp.to_i}#{payload}")
|
52
|
+
Base64.strict_encode64(sig)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.verify_header(payload, signatures_header, timestamp_header, secret, tolerance: nil)
|
56
|
+
timestamp, signatures = parse_timestampt_and_sigs(signatures_header, timestamp_header)
|
57
|
+
|
58
|
+
expected_sig = calculate_signature(timestamp, payload, secret)
|
59
|
+
unless signatures.any? { |sig| secure_compare(sig, expected_sig) }
|
60
|
+
header = { TIMESTAMP_HEADER => timestamp_header, SIGNATURE_HEADER => signatures_header }
|
61
|
+
raise Simplyq::SignatureVerificationError.new(
|
62
|
+
"No signatures found matching the expected signature for payload",
|
63
|
+
http_headers: header, http_body: payload
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
if tolerance && timestamp < Time.now - tolerance
|
68
|
+
header = { TIMESTAMP_HEADER => timestamp_header, SIGNATURE_HEADER => signatures_header }
|
69
|
+
raise SignatureVerificationError.new(
|
70
|
+
"Timestamp outside the tolerance zone (#{timestamp.to_i})",
|
71
|
+
http_headers: header, http_body: payload
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
true
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.parse_timestampt_and_sigs(signatures_header, timestamp_header)
|
79
|
+
timestamp = Integer(timestamp_header)
|
80
|
+
|
81
|
+
signatures = signatures_header.split(",").map(&:strip)
|
82
|
+
raise Simplyq::SignatureVerificationError.new("No signatures found", http_headers: header) if signatures.empty?
|
83
|
+
|
84
|
+
[Time.at(timestamp), signatures]
|
85
|
+
end
|
86
|
+
private_class_method :parse_timestampt_and_sigs
|
87
|
+
|
88
|
+
# Constant time string comparison to prevent timing attacks
|
89
|
+
# Code borrowed from ActiveSupport
|
90
|
+
def self.secure_compare(str_a, str_b)
|
91
|
+
return false unless str_a.bytesize == str_b.bytesize
|
92
|
+
|
93
|
+
l = str_a.unpack "C#{str_a.bytesize}"
|
94
|
+
|
95
|
+
res = 0
|
96
|
+
str_b.each_byte { |byte| res |= byte ^ l.shift }
|
97
|
+
res.zero?
|
98
|
+
end
|
99
|
+
private_class_method :secure_compare
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/simplyq.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Version
|
4
|
+
require_relative "simplyq/version"
|
5
|
+
|
6
|
+
# API resources support classes
|
7
|
+
require "simplyq/errors"
|
8
|
+
require "simplyq/client"
|
9
|
+
require "simplyq/configuration"
|
10
|
+
require "simplyq/webhook"
|
11
|
+
|
12
|
+
# API models
|
13
|
+
require "simplyq/models/list"
|
14
|
+
require "simplyq/models/application"
|
15
|
+
require "simplyq/models/endpoint"
|
16
|
+
require "simplyq/models/event"
|
17
|
+
require "simplyq/models/delivery_attempt"
|
18
|
+
require "simplyq/models/inbound_event"
|
19
|
+
|
20
|
+
# APIs
|
21
|
+
require "simplyq/api/application_api"
|
22
|
+
require "simplyq/api/endpoint_api"
|
23
|
+
require "simplyq/api/event_api"
|
24
|
+
|
25
|
+
module Simplyq
|
26
|
+
end
|
data/sig/simplyq.rbs
ADDED
data/simplyq.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/simplyq/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "simplyq"
|
7
|
+
spec.version = Simplyq::VERSION
|
8
|
+
spec.authors = ["simplyq-dxtimer"]
|
9
|
+
spec.email = ["ivan@simplyq.io"]
|
10
|
+
|
11
|
+
spec.summary = "The SimplyQ API client for Ruby"
|
12
|
+
spec.description = "The SimplyQ API client for Ruby"
|
13
|
+
spec.homepage = "https://github.com/simplyqio/apis"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 2.7"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/simplyqio/apis/tree/main/ruby"
|
19
|
+
spec.metadata["changelog_uri"] = "https://github.com/simplyqio/apis/tree/main/ruby/CHANGELOG.md"
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(__dir__) do
|
24
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
25
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features|examples)/|\.(?:git|travis|circleci)|appveyor)})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
spec.bindir = "exe"
|
29
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
30
|
+
spec.require_paths = ["lib"]
|
31
|
+
|
32
|
+
# Uncomment to register a new dependency of your gem
|
33
|
+
spec.add_dependency "faraday", [">= 0.15", "< 2.0"]
|
34
|
+
spec.add_dependency "multi_json", "~> 1.0"
|
35
|
+
spec.add_dependency "net-http-persistent"
|
36
|
+
# For more information and examples about making a new gem, check out our
|
37
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
38
|
+
# We are looking to automate the release process so MFA is not supported yet
|
39
|
+
# spec.metadata["rubygems_mfa_required"] = "true"
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simplyq
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.8.0rc
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- simplyq-dxtimer
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-11-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.15'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.15'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.0'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: multi_json
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.0'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: net-http-persistent
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
description: The SimplyQ API client for Ruby
|
62
|
+
email:
|
63
|
+
- ivan@simplyq.io
|
64
|
+
executables: []
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files: []
|
67
|
+
files:
|
68
|
+
- ".rspec"
|
69
|
+
- ".rubocop.yml"
|
70
|
+
- ".rubocop_todo.yml"
|
71
|
+
- ".tool-versions"
|
72
|
+
- CHANGELOG.md
|
73
|
+
- CODE_OF_CONDUCT.md
|
74
|
+
- Gemfile
|
75
|
+
- LICENSE.txt
|
76
|
+
- README.md
|
77
|
+
- Rakefile
|
78
|
+
- lib/simplyq.rb
|
79
|
+
- lib/simplyq/api/application_api.rb
|
80
|
+
- lib/simplyq/api/endpoint_api.rb
|
81
|
+
- lib/simplyq/api/event_api.rb
|
82
|
+
- lib/simplyq/client.rb
|
83
|
+
- lib/simplyq/configuration.rb
|
84
|
+
- lib/simplyq/errors.rb
|
85
|
+
- lib/simplyq/models/application.rb
|
86
|
+
- lib/simplyq/models/delivery_attempt.rb
|
87
|
+
- lib/simplyq/models/endpoint.rb
|
88
|
+
- lib/simplyq/models/event.rb
|
89
|
+
- lib/simplyq/models/inbound_event.rb
|
90
|
+
- lib/simplyq/models/list.rb
|
91
|
+
- lib/simplyq/version.rb
|
92
|
+
- lib/simplyq/webhook.rb
|
93
|
+
- sig/simplyq.rbs
|
94
|
+
- simplyq.gemspec
|
95
|
+
homepage: https://github.com/simplyqio/apis
|
96
|
+
licenses:
|
97
|
+
- MIT
|
98
|
+
metadata:
|
99
|
+
homepage_uri: https://github.com/simplyqio/apis
|
100
|
+
source_code_uri: https://github.com/simplyqio/apis/tree/main/ruby
|
101
|
+
changelog_uri: https://github.com/simplyqio/apis/tree/main/ruby/CHANGELOG.md
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options: []
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2.7'
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">"
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: 1.3.1
|
116
|
+
requirements: []
|
117
|
+
rubygems_version: 3.3.11
|
118
|
+
signing_key:
|
119
|
+
specification_version: 4
|
120
|
+
summary: The SimplyQ API client for Ruby
|
121
|
+
test_files: []
|