sendly 3.15.3 → 3.18.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30d293bb000beb6cf55425cf890c5d1a2aaf1763fd0924200208e64ece66a6aa
4
- data.tar.gz: b497dc439fab212a7b672f34912164909863dd5e6f3914b33e83d40bded4ca0e
3
+ metadata.gz: b45492ba74b05f9d480cea6a2a911c8b6ec9b66c5e197230a0a10ea81e4692f9
4
+ data.tar.gz: 981f6d67200e9725c9e0f546d65a9b575a3cfc4a1d5b935bd8f0c5c2034a1dd1
5
5
  SHA512:
6
- metadata.gz: 753b7db85a40604103a4036348b2f847328c2cb7bf7ce92614e032854350f6061500a2eaca36342f1245ffdb576441e4525577601a335e766e28ec12cc511a66
7
- data.tar.gz: c53e4e96bfb502a62250f36852239398c572a2770103fa559d077089e4649d064cbeabd4b04e9acf87260975d99571b1cdd3290539743320be67831d1d00bc85
6
+ metadata.gz: 7724bb3862a1b21aab27d4470b41b468585bfbce1fc73eb4f62c851afd710b8e24b54362cd2da64d6e3833b859717510220f4ccf502786330d04950f056fbe8f
7
+ data.tar.gz: e4319bb9b9a322d2b119e1dd1c6da32e68e4c178e2006a2987058a7a5af6112fde9a590aaeee18691ea7427b3b06f0e31be1a351d5e1d2b4ba51c9c89f12987f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sendly (3.15.3)
4
+ sendly (3.18.0)
5
5
  faraday (~> 2.0)
6
6
  faraday-retry (~> 2.0)
7
7
 
data/lib/sendly/client.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require "net/http"
4
4
  require "uri"
5
5
  require "json"
6
+ require "securerandom"
6
7
 
7
8
  module Sendly
8
9
  # Main Sendly API client
@@ -73,6 +74,13 @@ module Sendly
73
74
  @templates ||= TemplatesResource.new(self)
74
75
  end
75
76
 
77
+ # Access the Media resource
78
+ #
79
+ # @return [Sendly::Media]
80
+ def media
81
+ @media ||= Media.new(self)
82
+ end
83
+
76
84
  # Access the Campaigns resource
77
85
  #
78
86
  # @return [Sendly::CampaignsResource]
@@ -122,6 +130,60 @@ module Sendly
122
130
  request(:delete, path)
123
131
  end
124
132
 
133
+ # Make a multipart POST request for file uploads
134
+ #
135
+ # @param path [String] API path
136
+ # @param file [String, IO] File path or IO object
137
+ # @param content_type [String] MIME type of the file
138
+ # @param filename [String] Name for the uploaded file
139
+ # @return [Hash] Response body
140
+ def post_multipart(path, file, content_type: "image/jpeg", filename: "upload.jpg")
141
+ uri = build_uri(path, {})
142
+ http = build_http(uri)
143
+
144
+ boundary = "SendlyRuby#{SecureRandom.hex(16)}"
145
+
146
+ file_data = file.is_a?(String) ? File.binread(file) : file.read
147
+
148
+ body = []
149
+ body << "--#{boundary}\r\n"
150
+ body << "Content-Disposition: form-data; name=\"file\"; filename=\"#{filename}\"\r\n"
151
+ body << "Content-Type: #{content_type}\r\n\r\n"
152
+ body << file_data
153
+ body << "\r\n--#{boundary}--\r\n"
154
+
155
+ req = Net::HTTP::Post.new(uri)
156
+ req["Authorization"] = "Bearer #{api_key}"
157
+ req["Accept"] = "application/json"
158
+ req["User-Agent"] = "sendly-ruby/#{VERSION}"
159
+ req["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
160
+ req.body = body.join
161
+
162
+ attempt = 0
163
+ begin
164
+ response = http.request(req)
165
+ handle_response(response)
166
+ rescue Net::OpenTimeout, Net::ReadTimeout
167
+ raise TimeoutError, "Request timed out after #{timeout} seconds"
168
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET, SocketError => e
169
+ raise NetworkError, "Connection failed: #{e.message}"
170
+ rescue RateLimitError => e
171
+ attempt += 1
172
+ if attempt <= max_retries && e.retry_after
173
+ sleep(e.retry_after)
174
+ retry
175
+ end
176
+ raise
177
+ rescue ServerError => e
178
+ attempt += 1
179
+ if attempt <= max_retries
180
+ sleep(2 ** attempt)
181
+ retry
182
+ end
183
+ raise
184
+ end
185
+ end
186
+
125
187
  private
126
188
 
127
189
  def validate_api_key!
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sendly
4
+ class Media
5
+ attr_reader :client
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def upload(file, content_type: "image/jpeg", filename: "upload.jpg")
12
+ response = client.post_multipart("/media", file, content_type: content_type, filename: filename)
13
+ MediaFile.new(response)
14
+ end
15
+ end
16
+ end
@@ -36,13 +36,14 @@ module Sendly
36
36
  # text: "Your verification code is 123456",
37
37
  # message_type: "transactional"
38
38
  # )
39
- def send(to:, text:, message_type: nil, metadata: nil)
39
+ def send(to:, text:, message_type: nil, metadata: nil, media_urls: nil)
40
40
  validate_phone!(to)
41
41
  validate_text!(text)
42
42
 
43
43
  body = { to: to, text: text }
44
44
  body[:messageType] = message_type if message_type
45
45
  body[:metadata] = metadata if metadata
46
+ body[:mediaUrls] = media_urls if media_urls
46
47
 
47
48
  response = client.post("/messages", body)
48
49
  # API returns message directly at top level
data/lib/sendly/types.rb CHANGED
@@ -51,11 +51,17 @@ module Sendly
51
51
  # @return [Time, nil] Delivery timestamp
52
52
  attr_reader :delivered_at
53
53
 
54
+ # @return [String, nil] Error code if delivery failed
55
+ attr_reader :error_code
56
+
57
+ # @return [Integer] Number of delivery retry attempts
58
+ attr_reader :retry_count
59
+
54
60
  # @return [Hash, nil] Custom metadata attached to the message
55
61
  attr_reader :metadata
56
62
 
57
63
  # Message status constants (sending removed - doesn't exist in database)
58
- STATUSES = %w[queued sent delivered failed bounced].freeze
64
+ STATUSES = %w[queued sent delivered failed bounced retrying].freeze
59
65
 
60
66
  # Sender type constants
61
67
  SENDER_TYPES = %w[number_pool alphanumeric sandbox].freeze
@@ -77,6 +83,8 @@ module Sendly
77
83
  @sender_note = data["senderNote"]
78
84
  @created_at = parse_time(data["createdAt"])
79
85
  @delivered_at = parse_time(data["deliveredAt"])
86
+ @error_code = data["errorCode"]
87
+ @retry_count = data["retryCount"] || 0
80
88
  @metadata = data["metadata"]
81
89
  end
82
90
 
@@ -118,6 +126,8 @@ module Sendly
118
126
  sender_note: sender_note,
119
127
  created_at: created_at&.iso8601,
120
128
  delivered_at: delivered_at&.iso8601,
129
+ error_code: error_code,
130
+ retry_count: retry_count,
121
131
  metadata: metadata
122
132
  }.compact
123
133
  end
@@ -193,6 +203,30 @@ module Sendly
193
203
  end
194
204
  end
195
205
 
206
+ # ============================================================================
207
+ # Media
208
+ # ============================================================================
209
+
210
+ class MediaFile
211
+ attr_reader :id, :url, :content_type, :size_bytes
212
+
213
+ def initialize(data)
214
+ @id = data["id"]
215
+ @url = data["url"]
216
+ @content_type = data["contentType"]
217
+ @size_bytes = data["sizeBytes"]
218
+ end
219
+
220
+ def to_h
221
+ {
222
+ id: id,
223
+ url: url,
224
+ content_type: content_type,
225
+ size_bytes: size_bytes
226
+ }.compact
227
+ end
228
+ end
229
+
196
230
  # ============================================================================
197
231
  # Webhooks
198
232
  # ============================================================================
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sendly
4
- VERSION = "3.15.3"
4
+ VERSION = "3.18.0"
5
5
  end
data/lib/sendly.rb CHANGED
@@ -8,6 +8,7 @@ require_relative "sendly/errors"
8
8
  require_relative "sendly/types"
9
9
  require_relative "sendly/client"
10
10
  require_relative "sendly/messages"
11
+ require_relative "sendly/media"
11
12
  require_relative "sendly/webhooks"
12
13
  require_relative "sendly/webhooks_resource"
13
14
  require_relative "sendly/account_resource"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sendly
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.15.3
4
+ version: 3.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sendly
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-02-23 00:00:00.000000000 Z
11
+ date: 2026-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -128,6 +128,7 @@ files:
128
128
  - lib/sendly/client.rb
129
129
  - lib/sendly/contacts_resource.rb
130
130
  - lib/sendly/errors.rb
131
+ - lib/sendly/media.rb
131
132
  - lib/sendly/messages.rb
132
133
  - lib/sendly/templates_resource.rb
133
134
  - lib/sendly/types.rb