resend 0.25.0 → 0.26.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: 58501f77e4e315fec8185ee1a1b74942d0daa553ba4d13275e8efb0729780225
4
- data.tar.gz: ee0215aa0aa03241b817625736e26e99ff9c6194e19ff304b1cd0f12824bcd50
3
+ metadata.gz: 380fc77dd4f78646cea876d8a41c040c2456f5d83de51794adb366ae0cdf4c68
4
+ data.tar.gz: 6e868e3144a11781a20dcdd7fc2613e01885820d621595421845bceefee4c334
5
5
  SHA512:
6
- metadata.gz: f37730c78b2579ac2bf6b739504a20d6e6472430c4614a9ec22cedb134d5f19f440106f2f2c9d615eff4198e8be19292d10953a8af1e463a1465dc2051f68d76
7
- data.tar.gz: 68e4d7b0dc34700c1ddfee321f466f5a5f49319049cc2d54cb53a69063478941afab35907f9c66085caf56b96247bdf8da461117d677bdcae2898c8335cd019e
6
+ metadata.gz: 6aecfeb42d92ef7a7c90620a0a529f522b26c00b9341cdcf2ca0ae71c100710703b4162b96d4889f29a09825285a923ce1feaef465765ce2d060dffcf17405d4
7
+ data.tar.gz: c14fb10e9a778579ad5c1615899db85b90e2feba28a7b6441f0b3dcde4679a1d4bafe26ef93e9631ca2087540ade271687b174d797acad10afda53eacef4f10b
@@ -11,8 +11,8 @@ module Resend
11
11
  end
12
12
 
13
13
  # https://resend.com/docs/api-reference/api-keys/list-api-keys
14
- def list
15
- path = "api-keys"
14
+ def list(params = {})
15
+ path = Resend::PaginationHelper.build_paginated_path("api-keys", params)
16
16
  Resend::Request.new(path, {}, "get").perform
17
17
  end
18
18
 
@@ -17,8 +17,8 @@ module Resend
17
17
  end
18
18
 
19
19
  # https://resend.com/docs/api-reference/audiences/list-audiences
20
- def list
21
- path = "audiences"
20
+ def list(params = {})
21
+ path = Resend::PaginationHelper.build_paginated_path("audiences", params)
22
22
  Resend::Request.new(path, {}, "get").perform
23
23
  end
24
24
 
@@ -23,8 +23,8 @@ module Resend
23
23
  end
24
24
 
25
25
  # https://resend.com/docs/api-reference/broadcasts/list-broadcasts
26
- def list
27
- path = "broadcasts"
26
+ def list(params = {})
27
+ path = Resend::PaginationHelper.build_paginated_path("broadcasts", params)
28
28
  Resend::Request.new(path, {}, "get").perform
29
29
  end
30
30
 
@@ -26,9 +26,10 @@ module Resend
26
26
  # List contacts in an audience
27
27
  #
28
28
  # @param audience_id [String] the audience id
29
+ # @param params [Hash] optional pagination parameters
29
30
  # https://resend.com/docs/api-reference/contacts/list-contacts
30
- def list(audience_id)
31
- path = "audiences/#{audience_id}/contacts"
31
+ def list(audience_id, params = {})
32
+ path = Resend::PaginationHelper.build_paginated_path("audiences/#{audience_id}/contacts", params)
32
33
  Resend::Request.new(path, {}, "get").perform
33
34
  end
34
35
 
@@ -22,9 +22,9 @@ module Resend
22
22
  Resend::Request.new(path, {}, "get").perform
23
23
  end
24
24
 
25
- # https://resend.com/docs/api-reference/api-keys/list-api-keys
26
- def list
27
- path = "domains"
25
+ # https://resend.com/docs/api-reference/domains/list-domains
26
+ def list(params = {})
27
+ path = Resend::PaginationHelper.build_paginated_path("domains", params)
28
28
  Resend::Request.new(path, {}, "get").perform
29
29
  end
30
30
 
data/lib/resend/emails.rb CHANGED
@@ -31,6 +31,25 @@ module Resend
31
31
  path = "emails/#{email_id}/cancel"
32
32
  Resend::Request.new(path, {}, "post").perform
33
33
  end
34
+
35
+ # List emails with optional pagination.
36
+ # see more: https://resend.com/docs/api-reference/emails/list-emails
37
+ #
38
+ # @param options [Hash] Optional parameters for pagination
39
+ # @option options [Integer] :limit Maximum number of emails to return (1-100, default 20)
40
+ # @option options [String] :after Cursor for pagination (newer emails)
41
+ # @option options [String] :before Cursor for pagination (older emails)
42
+ def list(options = {})
43
+ path = "emails"
44
+
45
+ # Build query parameters, filtering out nil values
46
+ query_params = {}
47
+ query_params[:limit] = options[:limit] if options[:limit]
48
+ query_params[:after] = options[:after] if options[:after]
49
+ query_params[:before] = options[:before] if options[:before]
50
+
51
+ Resend::Request.new(path, query_params, "get").perform
52
+ end
34
53
  end
35
54
 
36
55
  # This method is kept here for backwards compatibility
data/lib/resend/errors.rb CHANGED
@@ -17,7 +17,17 @@ module Resend
17
17
  InvalidRequestError = Class.new(ServerError)
18
18
 
19
19
  # code 429
20
- RateLimitExceededError = Class.new(ServerError)
20
+ class RateLimitExceededError < ServerError
21
+ attr_reader :rate_limit_limit, :rate_limit_remaining, :rate_limit_reset, :retry_after
22
+
23
+ def initialize(msg, code = nil, headers = {})
24
+ super(msg, code, headers)
25
+ @rate_limit_limit = headers["ratelimit-limit"]&.to_i
26
+ @rate_limit_remaining = headers["ratelimit-remaining"]&.to_i
27
+ @rate_limit_reset = headers["ratelimit-reset"]&.to_i
28
+ @retry_after = headers["retry-after"]&.to_i
29
+ end
30
+ end
21
31
 
22
32
  # code 404
23
33
  NotFoundError = Class.new(ServerError)
@@ -31,9 +41,12 @@ module Resend
31
41
  500 => Resend::Error::InternalServerError
32
42
  }.freeze
33
43
 
34
- def initialize(msg, code = nil)
44
+ attr_reader :headers
45
+
46
+ def initialize(msg, code = nil, headers = {})
35
47
  super(msg)
36
48
  @code = code
49
+ @headers = headers
37
50
  end
38
51
  end
39
52
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resend
4
+ # Helper class for building paginated query strings
5
+ class PaginationHelper
6
+ class << self
7
+ # Builds a paginated path with query parameters
8
+ #
9
+ # @param base_path [String] the base API path
10
+ # @param query_params [Hash] optional pagination parameters
11
+ # @option query_params [Integer] :limit Number of items to retrieve (max 100)
12
+ # @option query_params [String] :after ID after which to retrieve more items
13
+ # @option query_params [String] :before ID before which to retrieve more items
14
+ # @return [String] the path with query parameters
15
+ def build_paginated_path(base_path, query_params = nil)
16
+ return base_path if query_params.nil? || query_params.empty?
17
+
18
+ # Filter out nil values and convert to string keys
19
+ filtered_params = query_params.compact.transform_keys(&:to_s)
20
+
21
+ # Build query string
22
+ query_string = filtered_params.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join("&")
23
+
24
+ return base_path if query_string.empty?
25
+
26
+ "#{base_path}?#{query_string}"
27
+ end
28
+ end
29
+ end
30
+ end
@@ -30,34 +30,51 @@ module Resend
30
30
 
31
31
  # Performs the HTTP call
32
32
  def perform
33
- options = {
34
- headers: @headers
35
- }
36
- options[:body] = @body.to_json unless @body.empty?
37
-
33
+ options = build_request_options
38
34
  resp = HTTParty.send(@verb.to_sym, "#{BASE_URL}#{@path}", options)
39
35
 
40
36
  check_json!(resp)
41
-
42
- resp.transform_keys!(&:to_sym) unless resp.body.empty?
43
- handle_error!(resp) if resp[:statusCode] && (resp[:statusCode] != 200 || resp[:statusCode] != 201)
44
- resp
37
+ process_response(resp)
45
38
  end
46
39
 
47
40
  def handle_error!(resp)
48
41
  code = resp[:statusCode]
49
42
  body = resp[:message]
43
+ headers = resp.respond_to?(:headers) ? resp.headers : (resp[:headers] || {})
50
44
 
51
45
  # get error from the known list of errors
52
- error = Resend::Error::ERRORS[code]
53
- raise(error.new(body, code)) if error
54
-
55
- # Raise generic Resend error when the error code is not part of the known errors
56
- raise Resend::Error.new(body, code)
46
+ error_class = Resend::Error::ERRORS[code] || Resend::Error
47
+ raise error_class.new(body, code, headers)
57
48
  end
58
49
 
59
50
  private
60
51
 
52
+ def build_request_options
53
+ options = { headers: @headers }
54
+
55
+ if get_request_with_query?
56
+ options[:query] = @body
57
+ elsif !@body.empty?
58
+ options[:body] = @body.to_json
59
+ end
60
+
61
+ options
62
+ end
63
+
64
+ def get_request_with_query?
65
+ @verb.downcase == "get" && !@body.empty?
66
+ end
67
+
68
+ def process_response(resp)
69
+ resp.transform_keys!(&:to_sym) unless resp.body.empty?
70
+ handle_error!(resp) if error_response?(resp)
71
+ resp
72
+ end
73
+
74
+ def error_response?(resp)
75
+ resp[:statusCode] && (resp[:statusCode] != 200 && resp[:statusCode] != 201)
76
+ end
77
+
61
78
  def set_idempotency_key
62
79
  # Only set idempotency key if the verb is POST for now.
63
80
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Resend
4
- VERSION = "0.25.0"
4
+ VERSION = "0.26.0"
5
5
  end
data/lib/resend.rb CHANGED
@@ -6,9 +6,11 @@ require "resend/version"
6
6
  # Utils
7
7
  require "httparty"
8
8
  require "json"
9
+ require "cgi"
9
10
  require "resend/errors"
10
11
  require "resend/client"
11
12
  require "resend/request"
13
+ require "resend/pagination_helper"
12
14
 
13
15
  # API Operations
14
16
  require "resend/audiences"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resend
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.25.0
4
+ version: 0.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Derich Pacheco
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-09-20 00:00:00.000000000 Z
11
+ date: 2025-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -56,6 +56,7 @@ files:
56
56
  - lib/resend/emails.rb
57
57
  - lib/resend/errors.rb
58
58
  - lib/resend/mailer.rb
59
+ - lib/resend/pagination_helper.rb
59
60
  - lib/resend/railtie.rb
60
61
  - lib/resend/request.rb
61
62
  - lib/resend/version.rb