twilio-ruby 5.1.0 → 5.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -0
- data/CHANGES.md +22 -0
- data/Makefile +2 -2
- data/README.md +19 -5
- data/lib/twilio-ruby/http/http_client.rb +1 -3
- data/lib/twilio-ruby/jwt/access_token.rb +35 -4
- data/lib/twilio-ruby/jwt/client_capability.rb +0 -2
- data/lib/twilio-ruby/jwt/jwt.rb +2 -1
- data/lib/twilio-ruby/jwt/task_router.rb +0 -4
- data/lib/twilio-ruby/rest/api/v2010/account/address.rb +9 -3
- data/lib/twilio-ruby/rest/video/v1/room.rb +3 -1
- data/lib/twilio-ruby/twiml/twiml.rb +1 -2
- data/lib/twilio-ruby/version.rb +1 -1
- data/spec/jwt/access_token_spec.rb +35 -16
- data/spec/twiml/messaging_response_spec.rb +5 -0
- data/spec/twiml/voice_response_spec.rb +5 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 399f522ccd4b51d8383070a32079b1414e9b18df
|
4
|
+
data.tar.gz: aea3e095d94d500c80fdaf3c2c7f9d7cda910619
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d09bebe465830e3d8bc71fa4f647885ea27814cd22a6b8a7b7522f0fc774102d6c37e4e44e012b777279700b5433dd48e36ff5fa097dfd558259d2f2abbb05f
|
7
|
+
data.tar.gz: 4b2ac197c38fda839f8836931a6986a80687a9212e75d6a74f875c20fbcc7509ff9e06ff424b08e44a7507e61b92791d30114e278e3066da8cee0c8b3f028082
|
data/.rubocop.yml
CHANGED
@@ -5,12 +5,20 @@ AllCops:
|
|
5
5
|
Exclude:
|
6
6
|
- 'lib/twilio-ruby/rest/**/*'
|
7
7
|
- 'spec/integration/**/*'
|
8
|
+
- 'lib/twilio-ruby/version.rb'
|
8
9
|
|
9
10
|
Metrics/LineLength:
|
10
11
|
Max: 120
|
11
12
|
Exclude:
|
12
13
|
- 'spec/**/*'
|
13
14
|
|
15
|
+
Metrics/BlockLength:
|
16
|
+
Exclude:
|
17
|
+
- 'spec/**/*'
|
18
|
+
|
19
|
+
Metrics/AbcSize:
|
20
|
+
Enabled: false
|
21
|
+
|
14
22
|
Metrics/ClassLength:
|
15
23
|
Max: 175
|
16
24
|
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
twilio-ruby changelog
|
2
2
|
=====================
|
3
|
+
|
4
|
+
[2017-08-10] Version 5.1.1
|
5
|
+
---------------------------
|
6
|
+
**Library**
|
7
|
+
- Don't override Faraday default param encoder. Thanks to @isaacseymour. PR #309
|
8
|
+
- Fix incorrectly aliased `to_xml` on TwiML classes. Thanks to @philnash. PR #318
|
9
|
+
- Only define `to_s` on BaseJWT instead of subclasses. Thanks to @philnash. PR #321
|
10
|
+
- Silence deprecation messages in testing. Thanks to @philnash. PR #323
|
11
|
+
|
12
|
+
**Api**
|
13
|
+
- Add New wireless usage keys added
|
14
|
+
- Add `auto_correct_address` param for Addresses create and update
|
15
|
+
|
16
|
+
**Video**
|
17
|
+
- Add `video_codec` enum and `video_codecs` parameter, which can be set to either `VP8` or `H264` during room creation.
|
18
|
+
- Restrict recordings page size to 100
|
19
|
+
|
20
|
+
**Chat**
|
21
|
+
- Add ChatGrant to available access tokens.
|
22
|
+
- Mark IpMessagingGrant as deprecated in favor of ChatGrant.
|
23
|
+
|
24
|
+
|
3
25
|
[2017-07-27] Version 5.1.0
|
4
26
|
---------------------------
|
5
27
|
This release adds Beta and Preview products to main artifact.
|
data/Makefile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
.PHONY: test lint-changed lint
|
1
|
+
.PHONY: test lint-changed lint docs
|
2
2
|
|
3
3
|
CHANGED_RUBY_FILES = $(shell git status --porcelain | grep ".rb" | awk -F ' ' '{print $2}' | tr '\n' ' ')
|
4
4
|
|
@@ -12,7 +12,7 @@ test: lint
|
|
12
12
|
bundle exec rake spec
|
13
13
|
|
14
14
|
docs:
|
15
|
-
yard doc
|
15
|
+
yard doc --output-dir ./doc
|
16
16
|
|
17
17
|
lint:
|
18
18
|
rubocop --cache true --parallel
|
data/README.md
CHANGED
@@ -6,18 +6,34 @@
|
|
6
6
|
|
7
7
|
A module for using the Twilio REST API and generating valid [TwiML](http://www.twilio.com/docs/api/twiml/ "TwiML - Twilio Markup Language"). [Click here to read the full documentation.][documentation]
|
8
8
|
|
9
|
+
## Recent Update
|
10
|
+
|
11
|
+
As of release 5.1.0, Beta and Developer Preview products are now exposed via
|
12
|
+
the main `twilio-java` artifact. Releases of the `alpha` branch have been
|
13
|
+
discontinued.
|
14
|
+
|
15
|
+
If you were using the `alpha` release line, you should be able to switch back
|
16
|
+
to the normal release line without issue.
|
17
|
+
|
18
|
+
If you were using the normal release line, you should now see several new
|
19
|
+
product lines that were historically hidden from you due to their Beta or
|
20
|
+
Developer Preview status. Such products are explicitly documented as
|
21
|
+
Beta/Developer Preview both in the Twilio docs and console, as well as through
|
22
|
+
in-line code documentation here in the library.
|
23
|
+
|
24
|
+
|
9
25
|
## Installation
|
10
26
|
|
11
27
|
To install using [Bundler][bundler] grab the latest stable version:
|
12
28
|
|
13
29
|
```ruby
|
14
|
-
gem 'twilio-ruby', '~> 5.1.
|
30
|
+
gem 'twilio-ruby', '~> 5.1.1'
|
15
31
|
```
|
16
32
|
|
17
33
|
To manually install `twilio-ruby` via [Rubygems][rubygems] simply gem install:
|
18
34
|
|
19
35
|
```bash
|
20
|
-
gem install twilio-ruby -v 5.1.
|
36
|
+
gem install twilio-ruby -v 5.1.1
|
21
37
|
```
|
22
38
|
|
23
39
|
To build and install the development branch yourself from the latest source:
|
@@ -120,8 +136,7 @@ section of the wiki.
|
|
120
136
|
|
121
137
|
## Getting Started With TwiML
|
122
138
|
|
123
|
-
|
124
|
-
TwiML response like this:
|
139
|
+
You can construct a TwiML response like this:
|
125
140
|
|
126
141
|
```ruby
|
127
142
|
require 'twilio-ruby'
|
@@ -161,7 +176,6 @@ implementations:
|
|
161
176
|
- Ruby 2.0.0
|
162
177
|
|
163
178
|
[capability]: https://github.com/twilio/twilio-ruby/wiki/Capability
|
164
|
-
[builder]: http://builder.rubyforge.org/
|
165
179
|
[examples]: https://github.com/twilio/twilio-ruby/blob/master/examples
|
166
180
|
[documentation]: http://twilio.github.io/twilio-ruby
|
167
181
|
[wiki]: https://github.com/twilio/twilio-ruby/wiki
|
@@ -12,13 +12,11 @@ module Twilio
|
|
12
12
|
@proxy_pass = proxy_pass
|
13
13
|
@ssl_ca_file = ssl_ca_file
|
14
14
|
@adapter = Faraday.default_adapter
|
15
|
-
|
16
|
-
# Set default params encoder
|
17
|
-
Faraday::Utils.default_params_encoder = Faraday::FlatParamsEncoder
|
18
15
|
end
|
19
16
|
|
20
17
|
def request(host, port, method, url, params = {}, data = {}, headers = {}, auth = nil, timeout = nil)
|
21
18
|
@connection = Faraday.new(url: host + ':' + port.to_s, ssl: { verify: true }) do |f|
|
19
|
+
f.options.params_encoder = Faraday::FlatParamsEncoder
|
22
20
|
f.request :url_encoded
|
23
21
|
f.adapter @adapter
|
24
22
|
f.headers = headers
|
@@ -50,10 +50,6 @@ module Twilio
|
|
50
50
|
@grants.push(grant)
|
51
51
|
end
|
52
52
|
|
53
|
-
def to_s
|
54
|
-
to_jwt
|
55
|
-
end
|
56
|
-
|
57
53
|
protected
|
58
54
|
|
59
55
|
def _generate_payload
|
@@ -81,6 +77,36 @@ module Twilio
|
|
81
77
|
headers
|
82
78
|
end
|
83
79
|
|
80
|
+
class ChatGrant
|
81
|
+
include AccessTokenGrant
|
82
|
+
attr_accessor :service_sid,
|
83
|
+
:endpoint_id,
|
84
|
+
:deployment_role_sid,
|
85
|
+
:push_credential_sid
|
86
|
+
|
87
|
+
def _key
|
88
|
+
'chat'
|
89
|
+
end
|
90
|
+
|
91
|
+
def _generate_payload
|
92
|
+
payload = {}
|
93
|
+
|
94
|
+
payload[:service_sid] = service_sid if service_sid
|
95
|
+
|
96
|
+
payload[:endpoint_id] = endpoint_id if endpoint_id
|
97
|
+
|
98
|
+
if deployment_role_sid
|
99
|
+
payload[:deployment_role_sid] = deployment_role_sid
|
100
|
+
end
|
101
|
+
|
102
|
+
if push_credential_sid
|
103
|
+
payload[:push_credential_sid] = push_credential_sid
|
104
|
+
end
|
105
|
+
|
106
|
+
payload
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
84
110
|
class IpMessagingGrant
|
85
111
|
include AccessTokenGrant
|
86
112
|
attr_accessor :service_sid,
|
@@ -109,6 +135,11 @@ module Twilio
|
|
109
135
|
|
110
136
|
payload
|
111
137
|
end
|
138
|
+
|
139
|
+
class << self
|
140
|
+
extend Gem::Deprecate
|
141
|
+
deprecate :new, 'Chat.new', 2017, 7
|
142
|
+
end
|
112
143
|
end
|
113
144
|
|
114
145
|
class VoiceGrant
|
@@ -12,8 +12,6 @@ module Twilio
|
|
12
12
|
:client_name,
|
13
13
|
:scopes
|
14
14
|
|
15
|
-
alias to_s to_jwt
|
16
|
-
|
17
15
|
def initialize(account_sid, auth_token, scopes: [], nbf: nil, ttl: 3600, valid_until: nil)
|
18
16
|
super(secret_key: auth_token, issuer: account_sid, nbf: nbf, ttl: ttl, valid_until: valid_until)
|
19
17
|
@account_sid = account_sid
|
data/lib/twilio-ruby/jwt/jwt.rb
CHANGED
@@ -38,13 +38,14 @@ module Twilio
|
|
38
38
|
payload[:nbf] = @nbf || Time.now.to_i
|
39
39
|
payload[:exp] = @valid_until.nil? ? Time.now.to_i + @ttl : @valid_until
|
40
40
|
payload[:sub] = @subject unless @subject.nil?
|
41
|
-
|
41
|
+
|
42
42
|
payload
|
43
43
|
end
|
44
44
|
|
45
45
|
def to_jwt
|
46
46
|
::JWT.encode payload, @secret_key, @algorithm, headers
|
47
47
|
end
|
48
|
+
alias to_s to_jwt
|
48
49
|
end
|
49
50
|
end
|
50
51
|
end
|
@@ -36,8 +36,9 @@ module Twilio
|
|
36
36
|
# @param [String] iso_country The iso_country
|
37
37
|
# @param [String] friendly_name The friendly_name
|
38
38
|
# @param [Boolean] emergency_enabled The emergency_enabled
|
39
|
+
# @param [Boolean] auto_correct_address The auto_correct_address
|
39
40
|
# @return [AddressInstance] Newly created AddressInstance
|
40
|
-
def create(customer_name: nil, street: nil, city: nil, region: nil, postal_code: nil, iso_country: nil, friendly_name: :unset, emergency_enabled: :unset)
|
41
|
+
def create(customer_name: nil, street: nil, city: nil, region: nil, postal_code: nil, iso_country: nil, friendly_name: :unset, emergency_enabled: :unset, auto_correct_address: :unset)
|
41
42
|
data = Twilio::Values.of({
|
42
43
|
'CustomerName' => customer_name,
|
43
44
|
'Street' => street,
|
@@ -47,6 +48,7 @@ module Twilio
|
|
47
48
|
'IsoCountry' => iso_country,
|
48
49
|
'FriendlyName' => friendly_name,
|
49
50
|
'EmergencyEnabled' => emergency_enabled,
|
51
|
+
'AutoCorrectAddress' => auto_correct_address,
|
50
52
|
})
|
51
53
|
|
52
54
|
payload = @version.create(
|
@@ -266,8 +268,9 @@ module Twilio
|
|
266
268
|
# @param [String] region The region
|
267
269
|
# @param [String] postal_code The postal_code
|
268
270
|
# @param [Boolean] emergency_enabled The emergency_enabled
|
271
|
+
# @param [Boolean] auto_correct_address The auto_correct_address
|
269
272
|
# @return [AddressInstance] Updated AddressInstance
|
270
|
-
def update(friendly_name: :unset, customer_name: :unset, street: :unset, city: :unset, region: :unset, postal_code: :unset, emergency_enabled: :unset)
|
273
|
+
def update(friendly_name: :unset, customer_name: :unset, street: :unset, city: :unset, region: :unset, postal_code: :unset, emergency_enabled: :unset, auto_correct_address: :unset)
|
271
274
|
data = Twilio::Values.of({
|
272
275
|
'FriendlyName' => friendly_name,
|
273
276
|
'CustomerName' => customer_name,
|
@@ -276,6 +279,7 @@ module Twilio
|
|
276
279
|
'Region' => region,
|
277
280
|
'PostalCode' => postal_code,
|
278
281
|
'EmergencyEnabled' => emergency_enabled,
|
282
|
+
'AutoCorrectAddress' => auto_correct_address,
|
279
283
|
})
|
280
284
|
|
281
285
|
payload = @version.update(
|
@@ -475,8 +479,9 @@ module Twilio
|
|
475
479
|
# @param [String] region The region
|
476
480
|
# @param [String] postal_code The postal_code
|
477
481
|
# @param [Boolean] emergency_enabled The emergency_enabled
|
482
|
+
# @param [Boolean] auto_correct_address The auto_correct_address
|
478
483
|
# @return [AddressInstance] Updated AddressInstance
|
479
|
-
def update(friendly_name: :unset, customer_name: :unset, street: :unset, city: :unset, region: :unset, postal_code: :unset, emergency_enabled: :unset)
|
484
|
+
def update(friendly_name: :unset, customer_name: :unset, street: :unset, city: :unset, region: :unset, postal_code: :unset, emergency_enabled: :unset, auto_correct_address: :unset)
|
480
485
|
context.update(
|
481
486
|
friendly_name: friendly_name,
|
482
487
|
customer_name: customer_name,
|
@@ -485,6 +490,7 @@ module Twilio
|
|
485
490
|
region: region,
|
486
491
|
postal_code: postal_code,
|
487
492
|
emergency_enabled: emergency_enabled,
|
493
|
+
auto_correct_address: auto_correct_address,
|
488
494
|
)
|
489
495
|
end
|
490
496
|
|
@@ -32,8 +32,9 @@ module Twilio
|
|
32
32
|
# @param [String] max_participants The max_participants
|
33
33
|
# @param [Boolean] record_participants_on_connect The
|
34
34
|
# record_participants_on_connect
|
35
|
+
# @param [room.VideoCodec] video_codecs The video_codecs
|
35
36
|
# @return [RoomInstance] Newly created RoomInstance
|
36
|
-
def create(enable_turn: :unset, type: :unset, unique_name: :unset, status_callback: :unset, status_callback_method: :unset, max_participants: :unset, record_participants_on_connect: :unset)
|
37
|
+
def create(enable_turn: :unset, type: :unset, unique_name: :unset, status_callback: :unset, status_callback_method: :unset, max_participants: :unset, record_participants_on_connect: :unset, video_codecs: :unset)
|
37
38
|
data = Twilio::Values.of({
|
38
39
|
'EnableTurn' => enable_turn,
|
39
40
|
'Type' => type,
|
@@ -42,6 +43,7 @@ module Twilio
|
|
42
43
|
'StatusCallbackMethod' => status_callback_method,
|
43
44
|
'MaxParticipants' => max_participants,
|
44
45
|
'RecordParticipantsOnConnect' => record_participants_on_connect,
|
46
|
+
'VideoCodecs' => video_codecs,
|
45
47
|
})
|
46
48
|
|
47
49
|
payload = @version.create(
|
@@ -11,8 +11,6 @@ module Twilio
|
|
11
11
|
attr_accessor :name
|
12
12
|
attr_accessor :indent
|
13
13
|
|
14
|
-
alias to_xml to_s
|
15
|
-
|
16
14
|
def initialize(indent: false, **keyword_args)
|
17
15
|
@name = self.class.name.split('::').last
|
18
16
|
@indent = indent
|
@@ -37,6 +35,7 @@ module Twilio
|
|
37
35
|
return ('<?xml version="1.0" encoding="UTF-8"?>' + xml) if xml_declaration
|
38
36
|
xml
|
39
37
|
end
|
38
|
+
alias to_xml to_s
|
40
39
|
|
41
40
|
def xml
|
42
41
|
# create XML element
|
data/lib/twilio-ruby/version.rb
CHANGED
@@ -42,18 +42,35 @@ describe Twilio::JWT::AccessToken do
|
|
42
42
|
end
|
43
43
|
|
44
44
|
it 'IpMessaging grant' do
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
Gem::Deprecate.skip_during do
|
46
|
+
ip_messaging_grant = Twilio::JWT::AccessToken::IpMessagingGrant.new
|
47
|
+
ip_messaging_grant.service_sid = 'SS123'
|
48
|
+
ip_messaging_grant.endpoint_id = 'EP123'
|
49
|
+
ip_messaging_grant.deployment_role_sid = 'DR123'
|
50
|
+
ip_messaging_grant.push_credential_sid = 'PC123'
|
51
|
+
@scat.add_grant(ip_messaging_grant)
|
52
|
+
payload, _ = JWT.decode @scat.to_s, 'secret'
|
53
|
+
expect(payload['grants'].count).to eq(1)
|
54
|
+
expect(payload['grants']['ip_messaging']['service_sid']).to eq('SS123')
|
55
|
+
expect(payload['grants']['ip_messaging']['endpoint_id']).to eq('EP123')
|
56
|
+
expect(payload['grants']['ip_messaging']['push_credential_sid']).to eq('PC123')
|
57
|
+
expect(payload['grants']['ip_messaging']['deployment_role_sid']).to eq('DR123')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'Chat grant' do
|
62
|
+
chat_grant = Twilio::JWT::AccessToken::ChatGrant.new
|
63
|
+
chat_grant.service_sid = 'SS123'
|
64
|
+
chat_grant.endpoint_id = 'EP123'
|
65
|
+
chat_grant.deployment_role_sid = 'DR123'
|
66
|
+
chat_grant.push_credential_sid = 'PC123'
|
67
|
+
@scat.add_grant(chat_grant)
|
51
68
|
payload, _ = JWT.decode @scat.to_s, 'secret'
|
52
69
|
expect(payload['grants'].count).to eq(1)
|
53
|
-
expect(payload['grants']['
|
54
|
-
expect(payload['grants']['
|
55
|
-
expect(payload['grants']['
|
56
|
-
expect(payload['grants']['
|
70
|
+
expect(payload['grants']['chat']['service_sid']).to eq('SS123')
|
71
|
+
expect(payload['grants']['chat']['endpoint_id']).to eq('EP123')
|
72
|
+
expect(payload['grants']['chat']['push_credential_sid']).to eq('PC123')
|
73
|
+
expect(payload['grants']['chat']['deployment_role_sid']).to eq('DR123')
|
57
74
|
end
|
58
75
|
|
59
76
|
it 'Voice grant' do
|
@@ -83,12 +100,14 @@ describe Twilio::JWT::AccessToken do
|
|
83
100
|
end
|
84
101
|
|
85
102
|
it 'Conversations grant' do
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
103
|
+
Gem::Deprecate.skip_during do
|
104
|
+
conversation_grant = Twilio::JWT::AccessToken::ConversationsGrant.new
|
105
|
+
conversation_grant.configuration_profile_sid = 'VS123'
|
106
|
+
@scat.add_grant(conversation_grant)
|
107
|
+
payload, _ = JWT.decode @scat.to_s, 'secret'
|
108
|
+
expect(payload['grants'].count).to eq(1)
|
109
|
+
expect(payload['grants']['rtc']['configuration_profile_sid']).to eq('VS123')
|
110
|
+
end
|
92
111
|
end
|
93
112
|
|
94
113
|
it 'Room grant' do
|
@@ -7,6 +7,11 @@ describe Twilio::TwiML::MessagingResponse do
|
|
7
7
|
expect(r.to_s).to eq('<?xml version="1.0" encoding="UTF-8"?><Response/>')
|
8
8
|
end
|
9
9
|
|
10
|
+
it 'should allow using to_xml instead of to_s' do
|
11
|
+
r = Twilio::TwiML::MessagingResponse.new
|
12
|
+
expect(r.to_xml).to eq('<?xml version="1.0" encoding="UTF-8"?><Response/>')
|
13
|
+
end
|
14
|
+
|
10
15
|
it 'should allow populated response' do
|
11
16
|
r = Twilio::TwiML::MessagingResponse.new
|
12
17
|
r.message(body: 'Hello')
|
@@ -7,6 +7,11 @@ describe Twilio::TwiML::VoiceResponse do
|
|
7
7
|
expect(r.to_s).to eq('<?xml version="1.0" encoding="UTF-8"?><Response/>')
|
8
8
|
end
|
9
9
|
|
10
|
+
it 'should allow using to_xml instead of to_s' do
|
11
|
+
r = Twilio::TwiML::VoiceResponse.new
|
12
|
+
expect(r.to_xml).to eq('<?xml version="1.0" encoding="UTF-8"?><Response/>')
|
13
|
+
end
|
14
|
+
|
10
15
|
it 'should allow populated response' do
|
11
16
|
r = Twilio::TwiML::VoiceResponse.new
|
12
17
|
r.hangup
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twilio-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.1.
|
4
|
+
version: 5.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Twilio API Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: libxml-ruby
|
@@ -604,7 +604,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
604
604
|
version: '0'
|
605
605
|
requirements: []
|
606
606
|
rubyforge_project:
|
607
|
-
rubygems_version: 2.
|
607
|
+
rubygems_version: 2.2.0
|
608
608
|
signing_key:
|
609
609
|
specification_version: 4
|
610
610
|
summary: A simple library for communicating with the Twilio REST API, building TwiML,
|