nexmo 6.1.0 → 7.1.1

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +24 -4
  4. data/lib/nexmo.rb +12 -14
  5. data/lib/nexmo/abstract_authentication.rb +2 -0
  6. data/lib/nexmo/account.rb +6 -1
  7. data/lib/nexmo/alerts.rb +6 -1
  8. data/lib/nexmo/applications.rb +24 -3
  9. data/lib/nexmo/applications/list_response.rb +2 -0
  10. data/lib/nexmo/authentication_error.rb +2 -0
  11. data/lib/nexmo/basic.rb +2 -0
  12. data/lib/nexmo/bearer_token.rb +1 -0
  13. data/lib/nexmo/client.rb +46 -23
  14. data/lib/nexmo/client_error.rb +2 -0
  15. data/lib/nexmo/config.rb +49 -9
  16. data/lib/nexmo/conversations.rb +24 -0
  17. data/lib/nexmo/conversations/events.rb +1 -0
  18. data/lib/nexmo/conversations/legs.rb +1 -0
  19. data/lib/nexmo/conversations/members.rb +1 -0
  20. data/lib/nexmo/conversations/users.rb +1 -0
  21. data/lib/nexmo/conversions.rb +4 -0
  22. data/lib/nexmo/entity.rb +5 -3
  23. data/lib/nexmo/error.rb +2 -0
  24. data/lib/nexmo/errors.rb +8 -0
  25. data/lib/nexmo/files.rb +7 -2
  26. data/lib/nexmo/form_data.rb +2 -0
  27. data/lib/nexmo/gsm7.rb +2 -0
  28. data/lib/nexmo/http.rb +12 -3
  29. data/lib/nexmo/json.rb +4 -0
  30. data/lib/nexmo/jwt.rb +5 -1
  31. data/lib/nexmo/key_secret_params.rb +10 -2
  32. data/lib/nexmo/keys.rb +7 -1
  33. data/lib/nexmo/logger.rb +14 -4
  34. data/lib/nexmo/messages.rb +7 -1
  35. data/lib/nexmo/namespace.rb +15 -18
  36. data/lib/nexmo/number_insight.rb +21 -6
  37. data/lib/nexmo/numbers.rb +24 -20
  38. data/lib/nexmo/numbers/list_response.rb +2 -0
  39. data/lib/nexmo/numbers/response.rb +1 -0
  40. data/lib/nexmo/params.rb +1 -0
  41. data/lib/nexmo/pricing.rb +2 -1
  42. data/lib/nexmo/pricing_types.rb +1 -0
  43. data/lib/nexmo/redact.rb +2 -1
  44. data/lib/nexmo/response.rb +2 -0
  45. data/lib/nexmo/secrets.rb +1 -0
  46. data/lib/nexmo/secrets/list_response.rb +2 -0
  47. data/lib/nexmo/server_error.rb +2 -0
  48. data/lib/nexmo/signature.rb +1 -0
  49. data/lib/nexmo/sms.rb +16 -10
  50. data/lib/nexmo/tfa.rb +2 -1
  51. data/lib/nexmo/user_agent.rb +1 -0
  52. data/lib/nexmo/verify.rb +93 -17
  53. data/lib/nexmo/version.rb +3 -1
  54. data/lib/nexmo/{calls.rb → voice.rb} +12 -11
  55. data/lib/nexmo/{calls → voice}/dtmf.rb +2 -1
  56. data/lib/nexmo/{calls → voice}/list_response.rb +3 -1
  57. data/lib/nexmo/{calls → voice}/stream.rb +2 -1
  58. data/lib/nexmo/{calls → voice}/talk.rb +2 -1
  59. data/nexmo.gemspec +2 -7
  60. metadata +17 -85
  61. data/lib/nexmo/key_secret_query.rb +0 -20
  62. data/lib/nexmo/number_insight/response.rb +0 -5
  63. data/lib/nexmo/sms/response.rb +0 -7
  64. data/lib/nexmo/verify/response.rb +0 -5
@@ -1,3 +1,5 @@
1
+ # typed: strong
2
+
1
3
  module Nexmo
2
4
  class ClientError < Error
3
5
  end
@@ -1,23 +1,30 @@
1
+ # typed: false
1
2
  # frozen_string_literal: true
2
3
  require 'logger'
3
4
 
4
5
  module Nexmo
5
6
  class Config
7
+ extend T::Sig
8
+
9
+ sig { void }
6
10
  def initialize
7
- self.api_key = ENV['NEXMO_API_KEY']
8
- self.api_secret = ENV['NEXMO_API_SECRET']
9
- self.application_id = nil
10
- self.logger = (defined?(Rails.logger) && Rails.logger) || ::Logger.new(nil)
11
- self.private_key = nil
11
+ self.api_host = 'api.nexmo.com'
12
+ self.api_key = T.let(ENV['NEXMO_API_KEY'], T.nilable(String))
13
+ self.api_secret = T.let(ENV['NEXMO_API_SECRET'], T.nilable(String))
14
+ self.application_id = ENV['NEXMO_APPLICATION_ID']
15
+ self.logger = (defined?(Rails.logger) && Rails.logger) || Nexmo::Logger.new(nil)
16
+ self.private_key = ENV['NEXMO_PRIVATE_KEY_PATH'] ? File.read(T.must(ENV['NEXMO_PRIVATE_KEY_PATH'])) : ENV['NEXMO_PRIVATE_KEY']
17
+ self.rest_host = 'rest.nexmo.com'
12
18
  self.signature_secret = ENV['NEXMO_SIGNATURE_SECRET']
13
19
  self.signature_method = ENV['NEXMO_SIGNATURE_METHOD'] || 'md5hash'
14
- self.token = nil
20
+ self.token = T.let(nil, T.nilable(String))
15
21
  end
16
22
 
17
23
  # Merges the config with the given options hash.
18
24
  #
19
25
  # @return [Nexmo::Config]
20
26
  #
27
+ sig { params(options: T.nilable(T::Hash[Symbol, T.untyped])).returns(Nexmo::Config) }
21
28
  def merge(options)
22
29
  return self if options.nil? || options.empty?
23
30
 
@@ -26,13 +33,18 @@ module Nexmo
26
33
  end
27
34
  end
28
35
 
36
+ sig { returns(String) }
37
+ attr_accessor :api_host
38
+
29
39
  # Returns the value of attribute api_key.
30
40
  #
31
41
  # @return [String]
32
42
  #
33
43
  # @raise [AuthenticationError]
34
44
  #
45
+ sig { returns(T.nilable(String)) }
35
46
  def api_key
47
+ @api_key = T.let(@api_key, T.nilable(String))
36
48
  unless @api_key
37
49
  raise AuthenticationError.new('No API key provided. ' \
38
50
  'See https://developer.nexmo.com/concepts/guides/authentication for details, ' \
@@ -42,6 +54,7 @@ module Nexmo
42
54
  @api_key
43
55
  end
44
56
 
57
+ sig { params(api_key: T.nilable(String)).returns(T.nilable(String)) }
45
58
  attr_writer :api_key
46
59
 
47
60
  # Returns the value of attribute api_secret.
@@ -50,7 +63,9 @@ module Nexmo
50
63
  #
51
64
  # @raise [AuthenticationError]
52
65
  #
66
+ sig { returns(T.nilable(String)) }
53
67
  def api_secret
68
+ @api_secret = T.let(@api_secret, T.nilable(String))
54
69
  unless @api_secret
55
70
  raise AuthenticationError.new('No API secret provided. ' \
56
71
  'See https://developer.nexmo.com/concepts/guides/authentication for details, ' \
@@ -60,6 +75,7 @@ module Nexmo
60
75
  @api_secret
61
76
  end
62
77
 
78
+ sig { params(api_secret: T.nilable(String)).returns(T.nilable(String)) }
63
79
  attr_writer :api_secret
64
80
 
65
81
  # Returns the value of attribute application_id.
@@ -68,7 +84,9 @@ module Nexmo
68
84
  #
69
85
  # @raise [AuthenticationError]
70
86
  #
87
+ sig { returns(T.nilable(String)) }
71
88
  def application_id
89
+ @application_id = T.let(@application_id, T.nilable(String))
72
90
  unless @application_id
73
91
  raise AuthenticationError.new('No application_id provided. ' \
74
92
  'Either provide an application_id, or set an auth token. ' \
@@ -80,32 +98,40 @@ module Nexmo
80
98
  @application_id
81
99
  end
82
100
 
101
+ sig { params(application_id: T.nilable(String)).returns(T.nilable(String)) }
83
102
  attr_writer :application_id
84
103
 
104
+ sig { returns(T.nilable(String)) }
85
105
  attr_accessor :app_name
86
106
 
107
+ sig { returns(T.nilable(String)) }
87
108
  attr_accessor :app_version
88
109
 
89
110
  # Returns the value of attribute http.
90
111
  #
91
112
  # @return [Nexmo::HTTP::Options]
92
113
  #
114
+ sig { returns(T.nilable(Nexmo::HTTP::Options)) }
93
115
  attr_reader :http
94
116
 
117
+ sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T.nilable(Nexmo::HTTP::Options)) }
95
118
  def http=(hash)
96
- @http = HTTP::Options.new(hash)
119
+ @http = T.let(nil, T.nilable(Nexmo::HTTP::Options))
120
+ @http = Nexmo::HTTP::Options.new(hash)
97
121
  end
98
122
 
99
123
  # Returns the value of attribute logger.
100
124
  #
101
125
  # @return [Nexmo::Logger]
102
126
  #
127
+ sig { returns(T.nilable(Nexmo::Logger)) }
103
128
  attr_reader :logger
104
129
 
105
130
  # @return [Nexmo::Logger]
106
131
  #
132
+ sig { params(logger: T.nilable(T.any(::Logger, Nexmo::Logger))).returns(T.nilable(Nexmo::Logger)) }
107
133
  def logger=(logger)
108
- @logger = Logger.new(logger)
134
+ @logger = T.let(Logger.new(logger), T.nilable(Nexmo::Logger))
109
135
  end
110
136
 
111
137
  # Returns the value of attribute private_key.
@@ -114,7 +140,9 @@ module Nexmo
114
140
  #
115
141
  # @raise [AuthenticationError]
116
142
  #
143
+ sig { returns(T.nilable(String)) }
117
144
  def private_key
145
+ @private_key = T.let(@private_key, T.nilable(String))
118
146
  unless @private_key
119
147
  raise AuthenticationError.new('No private_key provided. ' \
120
148
  'Either provide a private_key, or set an auth token. ' \
@@ -126,15 +154,21 @@ module Nexmo
126
154
  @private_key
127
155
  end
128
156
 
157
+ sig { params(private_key: T.nilable(String)).returns(T.nilable(String)) }
129
158
  attr_writer :private_key
130
159
 
160
+ sig { returns(String) }
161
+ attr_accessor :rest_host
162
+
131
163
  # Returns the value of attribute signature_secret.
132
164
  #
133
165
  # @return [String]
134
166
  #
135
167
  # @raise [AuthenticationError]
136
168
  #
169
+ sig { returns(T.nilable(String)) }
137
170
  def signature_secret
171
+ @signature_secret = T.let(@signature_secret, T.nilable(String))
138
172
  unless @signature_secret
139
173
  raise AuthenticationError.new('No signature_secret provided. ' \
140
174
  'You can find your signature secret in the Nexmo dashboard. ' \
@@ -145,22 +179,28 @@ module Nexmo
145
179
  @signature_secret
146
180
  end
147
181
 
182
+ sig { params(signature_secret: T.nilable(String)).returns(T.nilable(String)) }
148
183
  attr_writer :signature_secret
149
184
 
185
+ sig { returns(String) }
150
186
  attr_accessor :signature_method
151
187
 
152
188
  # Returns the value of attribute token, or a temporary short lived token.
153
189
  #
154
190
  # @return [String]
155
191
  #
192
+ sig { returns(T.nilable(String)) }
156
193
  def token
157
- @token || JWT.generate({application_id: application_id}, private_key)
194
+ @token = T.let(nil, T.nilable(String))
195
+ @token || JWT.generate({application_id: application_id}, T.must(private_key))
158
196
  end
159
197
 
198
+ sig { params(token: T.nilable(String)).returns(T.nilable(String)) }
160
199
  attr_writer :token
161
200
 
162
201
  protected
163
202
 
203
+ sig { params(name: Symbol, value: T.nilable(T.untyped)).void }
164
204
  def write_attribute(name, value)
165
205
  public_send(:"#{name}=", value)
166
206
  end
@@ -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,9 +1,11 @@
1
+ # typed: true
2
+
1
3
  module Nexmo
2
4
  class Entity
3
5
  include Keys
4
6
 
5
- def initialize(**kwargs)
6
- @attributes = kwargs
7
+ def initialize(attributes = nil)
8
+ @attributes = attributes || {}
7
9
  end
8
10
 
9
11
  def [](key)
@@ -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{|}~ ¡£¤¥§¿ÄÅÆÉÑÖØÜßàäåæçèéìñòöøùüΓΔΘΛΞΠΣΦΨΩ€"
@@ -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