nexmo 6.2.0 → 7.1.2

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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +21 -3
  3. data/lib/nexmo.rb +2 -0
  4. data/lib/nexmo/abstract_authentication.rb +2 -2
  5. data/lib/nexmo/account.rb +6 -1
  6. data/lib/nexmo/alerts.rb +6 -1
  7. data/lib/nexmo/applications.rb +24 -3
  8. data/lib/nexmo/applications/list_response.rb +2 -0
  9. data/lib/nexmo/authentication_error.rb +2 -0
  10. data/lib/nexmo/basic.rb +2 -0
  11. data/lib/nexmo/bearer_token.rb +1 -0
  12. data/lib/nexmo/client.rb +46 -23
  13. data/lib/nexmo/client_error.rb +2 -0
  14. data/lib/nexmo/config.rb +49 -9
  15. data/lib/nexmo/conversations.rb +24 -0
  16. data/lib/nexmo/conversations/events.rb +1 -0
  17. data/lib/nexmo/conversations/legs.rb +1 -0
  18. data/lib/nexmo/conversations/members.rb +1 -0
  19. data/lib/nexmo/conversations/users.rb +1 -0
  20. data/lib/nexmo/conversions.rb +4 -0
  21. data/lib/nexmo/entity.rb +3 -1
  22. data/lib/nexmo/error.rb +2 -0
  23. data/lib/nexmo/errors.rb +8 -0
  24. data/lib/nexmo/files.rb +7 -2
  25. data/lib/nexmo/form_data.rb +2 -0
  26. data/lib/nexmo/gsm7.rb +2 -2
  27. data/lib/nexmo/http.rb +12 -3
  28. data/lib/nexmo/json.rb +4 -0
  29. data/lib/nexmo/jwt.rb +5 -1
  30. data/lib/nexmo/key_secret_params.rb +10 -2
  31. data/lib/nexmo/keys.rb +7 -1
  32. data/lib/nexmo/logger.rb +14 -4
  33. data/lib/nexmo/messages.rb +7 -1
  34. data/lib/nexmo/namespace.rb +15 -18
  35. data/lib/nexmo/number_insight.rb +21 -6
  36. data/lib/nexmo/numbers.rb +2 -1
  37. data/lib/nexmo/numbers/list_response.rb +2 -0
  38. data/lib/nexmo/numbers/response.rb +1 -0
  39. data/lib/nexmo/params.rb +1 -0
  40. data/lib/nexmo/pricing.rb +2 -1
  41. data/lib/nexmo/pricing_types.rb +1 -0
  42. data/lib/nexmo/redact.rb +1 -0
  43. data/lib/nexmo/response.rb +2 -0
  44. data/lib/nexmo/secrets.rb +1 -0
  45. data/lib/nexmo/secrets/list_response.rb +2 -0
  46. data/lib/nexmo/server_error.rb +2 -0
  47. data/lib/nexmo/signature.rb +1 -0
  48. data/lib/nexmo/sms.rb +16 -10
  49. data/lib/nexmo/tfa.rb +2 -1
  50. data/lib/nexmo/user_agent.rb +1 -0
  51. data/lib/nexmo/verify.rb +93 -17
  52. data/lib/nexmo/version.rb +3 -1
  53. data/lib/nexmo/{calls.rb → voice.rb} +12 -11
  54. data/lib/nexmo/{calls → voice}/dtmf.rb +2 -1
  55. data/lib/nexmo/{calls → voice}/list_response.rb +3 -1
  56. data/lib/nexmo/{calls → voice}/stream.rb +2 -1
  57. data/lib/nexmo/{calls → voice}/talk.rb +2 -1
  58. data/nexmo.gemspec +1 -0
  59. metadata +22 -11
  60. data/lib/nexmo/number_insight/response.rb +0 -5
  61. data/lib/nexmo/sms/response.rb +0 -7
  62. data/lib/nexmo/verify/response.rb +0 -5
@@ -1,7 +1,10 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Nexmo
4
5
  class Conversations < Namespace
6
+ extend T::Sig
7
+
5
8
  self.authentication = BearerToken
6
9
 
7
10
  self.request_body = JSON
@@ -32,6 +35,7 @@ module Nexmo
32
35
  #
33
36
  # @see https://developer.nexmo.com/api/conversation#createConversation
34
37
  #
38
+ sig { params(params: T::Hash[Symbol, T.untyped]).returns(Nexmo::Response) }
35
39
  def create(params)
36
40
  request('/beta/conversations', params: params, type: Post)
37
41
  end
@@ -62,6 +66,7 @@ module Nexmo
62
66
  #
63
67
  # @see https://developer.nexmo.com/api/conversation#replaceConversation
64
68
  #
69
+ sig { params(params: T.nilable(T::Hash[Symbol, T.untyped])).returns(Nexmo::Response) }
65
70
  def list(params = nil)
66
71
  request('/beta/conversations', params: params)
67
72
  end
@@ -77,6 +82,7 @@ module Nexmo
77
82
  #
78
83
  # @see https://developer.nexmo.com/api/conversation#retrieveConversation
79
84
  #
85
+ sig { params(id: String).returns(Nexmo::Response) }
80
86
  def get(id)
81
87
  request('/beta/conversations/' + id)
82
88
  end
@@ -109,6 +115,10 @@ module Nexmo
109
115
  #
110
116
  # @see https://developer.nexmo.com/api/conversation#replaceConversation
111
117
  #
118
+ sig { params(
119
+ id: String,
120
+ params: T::Hash[Symbol, T.untyped]
121
+ ).returns(Nexmo::Response) }
112
122
  def update(id, params)
113
123
  request('/beta/conversations/' + id, params: params, type: Put)
114
124
  end
@@ -124,6 +134,7 @@ module Nexmo
124
134
  #
125
135
  # @see https://developer.nexmo.com/api/conversation#deleteConversation
126
136
  #
137
+ sig { params(id: String).returns(Nexmo::Response) }
127
138
  def delete(id)
128
139
  request('/beta/conversations/' + id, type: Delete)
129
140
  end
@@ -155,31 +166,44 @@ module Nexmo
155
166
  #
156
167
  # @see https://developer.nexmo.com/api/conversation#recordConversation
157
168
  #
169
+ sig { params(
170
+ id: String,
171
+ params: T::Hash[Symbol, T.untyped]
172
+ ).returns(Nexmo::Response) }
158
173
  def record(id, params)
159
174
  request('/v1/conversations/' + id + '/record', params: params, type: Put)
160
175
  end
161
176
 
162
177
  # @return [Events]
163
178
  #
179
+ sig { returns(T.nilable(Nexmo::Conversations::Events)) }
164
180
  def events
181
+ @events = T.let(@events, T.nilable(Nexmo::Conversations::Events))
182
+ @config = T.let(@config, T.nilable(Nexmo::Config))
165
183
  @events ||= Events.new(@config)
166
184
  end
167
185
 
168
186
  # @return [Legs]
169
187
  #
188
+ sig { returns(T.nilable(Nexmo::Conversations::Legs)) }
170
189
  def legs
190
+ @legs = T.let(@legs, T.nilable(Nexmo::Conversations::Legs))
171
191
  @legs ||= Legs.new(@config)
172
192
  end
173
193
 
174
194
  # @return [Members]
175
195
  #
196
+ sig { returns(T.nilable(Nexmo::Conversations::Members)) }
176
197
  def members
198
+ @members = T.let(@members, T.nilable(Nexmo::Conversations::Members))
177
199
  @members ||= Members.new(@config)
178
200
  end
179
201
 
180
202
  # @return [Users]
181
203
  #
204
+ sig { returns(T.nilable(Nexmo::Conversations::Users)) }
182
205
  def users
206
+ @users = T.let(@users, T.nilable(Nexmo::Conversations::Users))
183
207
  @users ||= Users.new(@config)
184
208
  end
185
209
  end
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Nexmo
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Nexmo
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Nexmo
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Nexmo
@@ -1,13 +1,17 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Nexmo
4
5
  class Conversions < Namespace
6
+ extend T::Sig
5
7
  include Keys
6
8
 
9
+ sig { params(params: T::Hash[Symbol, T.untyped]).returns(Nexmo::Response) }
7
10
  def track_sms(params)
8
11
  request('/conversions/sms', params: hyphenate(params), type: Post)
9
12
  end
10
13
 
14
+ sig { params(params: T::Hash[Symbol, T.untyped]).returns(Nexmo::Response) }
11
15
  def track_voice(params)
12
16
  request('/conversions/voice', params: hyphenate(params), type: Post)
13
17
  end
@@ -1,3 +1,5 @@
1
+ # typed: true
2
+
1
3
  module Nexmo
2
4
  class Entity
3
5
  include Keys
@@ -46,4 +48,4 @@ module Nexmo
46
48
 
47
49
  include Enumerable
48
50
  end
49
- end
51
+ end
@@ -1,3 +1,5 @@
1
+ # typed: strong
2
+
1
3
  module Nexmo
2
4
  class Error < StandardError
3
5
  end
@@ -1,8 +1,12 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
  require 'json'
3
4
 
4
5
  module Nexmo
5
6
  module Errors
7
+ extend T::Sig
8
+
9
+ sig {params(response: T.any(Net::HTTPUnauthorized, Net::HTTPClientError, Net::HTTPServerError, T.untyped)).returns(Nexmo::Error)}
6
10
  def self.parse(response)
7
11
  exception_class = case response
8
12
  when Net::HTTPUnauthorized
@@ -20,6 +24,8 @@ module Nexmo
20
24
 
21
25
  if hash.key?('error_title')
22
26
  hash['error_title']
27
+ elsif hash.key?('error-code-label')
28
+ hash['error-code-label']
23
29
  elsif hash.key?('description')
24
30
  hash['description']
25
31
  elsif problem_details?(hash)
@@ -30,10 +36,12 @@ module Nexmo
30
36
  exception_class.new(message)
31
37
  end
32
38
 
39
+ sig { params(hash: T::Hash[String, T.untyped]).returns(T::Boolean) }
33
40
  def self.problem_details?(hash)
34
41
  hash.key?('title') && hash.key?('detail') && hash.key?('type')
35
42
  end
36
43
 
44
+ sig { params(hash: T::Hash[String, T.untyped]).returns(String) }
37
45
  def self.problem_details_message(hash)
38
46
  "#{hash['title']}. #{hash['detail']} See #{hash['type']} for more info, or email support@nexmo.com if you have any questions."
39
47
  end
@@ -1,15 +1,20 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Nexmo
4
5
  class Files < Namespace
6
+ extend T::Sig
7
+
5
8
  self.authentication = BearerToken
6
9
 
10
+ sig { params(id: String).returns(T.nilable(Nexmo::Response)) }
7
11
  def get(id)
8
- request('/v1/files/' + id.split('/').last)
12
+ request('/v1/files/' + T.must(id.split('/').last))
9
13
  end
10
14
 
15
+ sig { params(id: String, filename: String).returns(T.nilable(Nexmo::Response)) }
11
16
  def save(id, filename)
12
- request('/v1/files/' + id.split('/').last) do |response|
17
+ request('/v1/files/' + T.must(id.split('/').last)) do |response|
13
18
  File.open(filename, 'wb') do |file|
14
19
  response.read_body do |chunk|
15
20
  file.write(chunk)
@@ -1,3 +1,5 @@
1
+ # typed: ignore
2
+
1
3
  module Nexmo
2
4
  module FormData
3
5
  def self.update(http_request, params)
@@ -1,3 +1,5 @@
1
+ # typed: ignore
2
+
1
3
  module Nexmo
2
4
  module GSM7
3
5
  CHARACTERS = "\n\f\r !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_abcdefghijklmnopqrstuvwxyz{|}~ ¡£¤¥§¿ÄÅÆÉÑÖØÜßàäåæçèéìñòöøùüΓΔΘΛΞΠΣΦΨΩ€"
@@ -8,6 +10,4 @@ module Nexmo
8
10
  REGEXP =~ string
9
11
  end
10
12
  end
11
-
12
- private_constant :GSM7
13
13
  end
@@ -1,11 +1,18 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
  require 'net/http'
3
4
 
4
5
  module Nexmo
5
6
  module HTTP
6
7
  class Options
8
+ extend T::Sig
9
+
10
+ sig { params(hash: T::Hash[Symbol, T.untyped]).void }
7
11
  def initialize(hash)
8
- @hash = hash || {}
12
+ raise ArgumentError, 'hash parameter cannot be empty or nil' if hash == {} || hash.nil?
13
+
14
+ @hash = T.let(@hash, T::Hash[Symbol, T.untyped]) if defined? @hash
15
+ @hash = hash
9
16
 
10
17
  @hash.each_key do |name|
11
18
  next if defined_options.key?(name)
@@ -14,6 +21,7 @@ module Nexmo
14
21
  end
15
22
  end
16
23
 
24
+ sig { params(http: Net::HTTP).returns(T::Hash[Symbol, T.untyped]) }
17
25
  def set(http)
18
26
  @hash.each do |name, value|
19
27
  http.public_send(defined_options.fetch(name), value)
@@ -22,13 +30,14 @@ module Nexmo
22
30
 
23
31
  private
24
32
 
33
+ sig { returns(T::Hash[Symbol, T.untyped]) }
25
34
  def defined_options
35
+ @defined_options = T.let(@defined_options, T.nilable(T::Hash[Symbol, T.untyped]))
36
+
26
37
  @defined_options ||= Net::HTTP.instance_methods.grep(/\w=\z/).each_with_object({}) do |name, hash|
27
38
  hash[name.to_s.chomp('=').to_sym] = name
28
39
  end
29
40
  end
30
41
  end
31
42
  end
32
-
33
- private_constant :HTTP
34
43
  end
@@ -1,8 +1,12 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
  require 'json'
3
4
 
4
5
  module Nexmo
5
6
  module JSON
7
+ extend T::Sig
8
+
9
+ sig { params(http_request: T.any(Net::HTTP::Put, Net::HTTP::Post), params: T::Hash[Symbol, T.untyped]).void }
6
10
  def self.update(http_request, params)
7
11
  http_request['Content-Type'] = 'application/json'
8
12
  http_request.body = ::JSON.generate(params)
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
  require 'securerandom'
3
4
  require 'openssl'
@@ -5,6 +6,8 @@ require 'jwt'
5
6
 
6
7
  module Nexmo
7
8
  module JWT
9
+ extend T::Sig
10
+
8
11
  # Generate an encoded JSON Web Token.
9
12
  #
10
13
  # By default the Nexmo Ruby SDK generates a short lived JWT per request.
@@ -30,9 +33,10 @@ module Nexmo
30
33
  #
31
34
  # @return [String]
32
35
  #
36
+ sig { params(payload: T::Hash[T.any(Symbol, String), T.any(String, Integer)], private_key: T.any(OpenSSL::PKey::RSA, String)).returns(String) }
33
37
  def self.generate(payload, private_key)
34
38
  payload[:iat] = iat = Time.now.to_i unless payload.key?(:iat) || payload.key?('iat')
35
- payload[:exp] = iat + 60 unless payload.key?(:exp) || payload.key?('exp')
39
+ payload[:exp] = T.must(iat) + 60 unless payload.key?(:exp) || payload.key?('exp')
36
40
  payload[:jti] = SecureRandom.uuid unless payload.key?(:jti) || payload.key?('jti')
37
41
 
38
42
  private_key = OpenSSL::PKey::RSA.new(private_key) unless private_key.respond_to?(:sign)
@@ -1,10 +1,18 @@
1
+ # typed: strict
2
+
1
3
  module Nexmo
2
4
  class KeySecretParams < AbstractAuthentication
5
+ extend T::Sig
6
+
7
+ sig { params(
8
+ object: T.any(T::Hash[T.untyped, T.untyped], URI::HTTPS, Net::HTTP::Post, Net::HTTP::Get)
9
+ ).void }
3
10
  def update(object)
4
11
  return unless object.is_a?(Hash)
5
12
 
6
- object[:api_key] = @config.api_key
7
- object[:api_secret] = @config.api_secret
13
+ @config = T.let(@config, T.nilable(Nexmo::Config))
14
+ object[:api_key] = T.must(@config).api_key
15
+ object[:api_secret] = T.must(@config).api_secret
8
16
  end
9
17
  end
10
18
 
@@ -1,16 +1,21 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Nexmo
4
5
  module Keys
6
+ extend T::Sig
7
+
8
+ sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T::Hash[String, T.untyped]) }
5
9
  def hyphenate(hash)
6
10
  hash.transform_keys { |k| k.to_s.tr('_', '-') }
7
11
  end
8
12
 
13
+ sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T::Hash[String, T.untyped]) }
9
14
  def camelcase(hash)
10
15
  hash.transform_keys { |k| k.to_s.gsub(/_(\w)/) { $1.upcase } }
11
16
  end
12
17
 
13
- ATTRIBUTE_KEYS = Hash.new { |h, k| h[k] = k.split(PATTERN).join('_').downcase.to_sym }
18
+ ATTRIBUTE_KEYS = T.let(Hash.new { |h, k| h[k] = k.split(PATTERN).join('_').downcase.to_sym }, T::Hash[T.untyped, T.untyped])
14
19
 
15
20
  PATTERN = /[\-_]|(?<=\w)(?=[A-Z])/
16
21
 
@@ -18,6 +23,7 @@ module Nexmo
18
23
 
19
24
  private_constant :PATTERN
20
25
 
26
+ sig { params(k: T.any(Symbol, String)).returns(Symbol) }
21
27
  def attribute_key(k)
22
28
  return k if k.is_a?(Symbol)
23
29
 
@@ -1,9 +1,13 @@
1
+ # typed: false
1
2
  # frozen_string_literal: true
2
3
  require 'logger'
3
4
  require 'forwardable'
4
5
 
5
6
  module Nexmo
6
7
  class Logger
8
+ extend T::Sig
9
+
10
+ sig { params(logger: T.nilable(T.any(::Logger, Nexmo::Logger))).void }
7
11
  def initialize(logger)
8
12
  @logger = logger || ::Logger.new(nil)
9
13
  end
@@ -14,8 +18,11 @@ module Nexmo
14
18
  def_delegator :@logger, name, name
15
19
  end
16
20
 
21
+ sig { params(request: T.any(Net::HTTP::Post, Net::HTTP::Get, Net::HTTP::Delete, Net::HTTP::Put)).void }
17
22
  def log_request_info(request)
18
- info do
23
+ @logger = T.let(@logger, T.nilable(T.any(::Logger, Nexmo::Logger)))
24
+
25
+ T.must(@logger).info do
19
26
  format('Nexmo API request', {
20
27
  method: request.method,
21
28
  path: request.uri.path
@@ -23,8 +30,12 @@ module Nexmo
23
30
  end
24
31
  end
25
32
 
33
+ sig { params(
34
+ response: T.any(Net::HTTPOK, Net::HTTPNoContent, Net::HTTPBadRequest, Net::HTTPInternalServerError, Net::HTTPResponse),
35
+ host: String
36
+ ).void }
26
37
  def log_response_info(response, host)
27
- info do
38
+ T.must(@logger).info do
28
39
  format('Nexmo API response', {
29
40
  host: host,
30
41
  status: response.code,
@@ -37,6 +48,7 @@ module Nexmo
37
48
 
38
49
  private
39
50
 
51
+ sig { params(message: String, hash: T::Hash[Symbol, T.untyped]).returns(String) }
40
52
  def format(message, hash)
41
53
  return message if hash.nil?
42
54
 
@@ -45,6 +57,4 @@ module Nexmo
45
57
  fields.join(' ')
46
58
  end
47
59
  end
48
-
49
- private_constant :Logger
50
60
  end
@@ -1,17 +1,23 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Nexmo
4
5
  class Messages < Namespace
5
- self.host = 'rest.nexmo.com'
6
+ extend T::Sig
6
7
 
8
+ self.host = :rest_host
9
+
10
+ sig { params(id: String).returns(Nexmo::Response) }
7
11
  def get(id)
8
12
  request('/search/message', params: {id: id})
9
13
  end
10
14
 
15
+ sig { params(params: T::Hash[Symbol, T.untyped]).returns(Nexmo::Response) }
11
16
  def search(params)
12
17
  request('/search/messages', params: params)
13
18
  end
14
19
 
20
+ sig { params(params: T::Hash[Symbol, T.untyped]).returns(Nexmo::Response) }
15
21
  def rejections(params)
16
22
  request('/search/rejections', params: params)
17
23
  end