nexmo 6.1.0 → 7.1.1

Sign up to get free protection for your applications and to get access to all the features.
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