resend 1.0.0 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9388a0e6d79027b6f057669d807519fdb74433d89eafc50bd0a4db5d4626e7a5
4
- data.tar.gz: 321c0387aa19dbf95b930ad5a79a00e40d09757714250aa44845b0f7e912efb4
3
+ metadata.gz: 67dadb5f7acb77801501030612149bf52b6c46626fd5630a233a77ab6fc552d7
4
+ data.tar.gz: 8842020484f59a566282b8ff1258bfeea02594274b2f117c548ae2ad49284ad2
5
5
  SHA512:
6
- metadata.gz: 51e5ffc36f521db854067a10d6bb2e0e90d45837237177bb5620ff189b015595695b55c122cccefd020f4dae2d23c6cca7221c4ee7346863eda3c05a297c8740
7
- data.tar.gz: 80637728c8fb04c3e521b79fd444cb3f92554062312070e324004863ee914fcea4da7d13be832ae6c4abcabedab0521e20e16e32dd778633a8a7169fb0d57732
6
+ metadata.gz: d889989325170107795bed29b590b45382909a8b4812381c4fa330e8c94c6cf7d8c3be1474793c0b6a93c85fc3f0647fd868f5b540902cd9e6ca260821f3b5ec
7
+ data.tar.gz: 48ec677afd58504f02b4099fb1f4d926defa2aa64f05cb2d8e8e1c724b08f1d1b3950f79535ac89481a8f58f1b1884962c4e46247bbdb6b03e0364325822fab9
@@ -7,6 +7,9 @@ module Resend
7
7
  # https://resend.com/docs/api-reference/broadcasts/create-broadcast
8
8
  # @note Supports both segment_id and audience_id. At least one is required.
9
9
  # audience_id is deprecated - use segment_id instead.
10
+ # @note When send: true is passed, the broadcast is sent immediately instead of
11
+ # creating a draft. When using send: true, you can also include scheduled_at
12
+ # to schedule the broadcast. Passing scheduled_at without send: true is an error.
10
13
  def create(params = {})
11
14
  if params[:audience_id] && !params[:segment_id]
12
15
  warn "[DEPRECATION] Using audience_id in broadcasts is deprecated. Use segment_id instead."
data/lib/resend/mailer.rb CHANGED
@@ -14,7 +14,7 @@ module Resend
14
14
  cc bcc
15
15
  from reply-to to subject mime-version
16
16
  html text
17
- content-type tags scheduled_at
17
+ content-type content-transfer-encoding tags scheduled_at
18
18
  headers options
19
19
  ].freeze
20
20
 
@@ -34,13 +34,16 @@ module Resend
34
34
  resp = HTTParty.send(@verb.to_sym, "#{BASE_URL}#{@path}", options)
35
35
 
36
36
  check_json!(resp)
37
- process_response(resp)
37
+ data = process_response(resp)
38
+ headers = extract_headers(resp)
39
+
40
+ Resend::Response.new(data, headers)
38
41
  end
39
42
 
40
- def handle_error!(resp)
41
- code = resp[:statusCode]
42
- body = resp[:message]
43
- headers = resp.respond_to?(:headers) ? resp.headers : (resp[:headers] || {})
43
+ def handle_error!(data, resp = nil)
44
+ code = data[:statusCode]
45
+ body = data[:message]
46
+ headers = resp.respond_to?(:headers) ? resp.headers : (data[:headers] || {})
44
47
 
45
48
  # get error from the known list of errors
46
49
  error_class = Resend::Error::ERRORS[code] || Resend::Error
@@ -66,20 +69,23 @@ module Resend
66
69
  end
67
70
 
68
71
  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
+ # Extract the parsed data from HTTParty response or use the hash directly (for tests/mocks)
73
+ data = resp.respond_to?(:parsed_response) ? resp.parsed_response : resp
74
+ data ||= {}
75
+ data.transform_keys!(&:to_sym) unless resp.body.empty?
76
+ handle_error!(data, resp) if error_response?(data)
77
+ data
72
78
  end
73
79
 
74
80
  def error_response?(resp)
75
- resp[:statusCode] && (resp[:statusCode] != 200 && resp[:statusCode] != 201)
81
+ resp[:statusCode] && resp[:statusCode] != 200 && resp[:statusCode] != 201
76
82
  end
77
83
 
78
84
  def set_idempotency_key
79
85
  # Only set idempotency key if the verb is POST for now.
80
86
  #
81
87
  # Does not set it if the idempotency_key is nil or empty
82
- if @verb.downcase == "post" && (!@options[:idempotency_key].nil? && !@options[:idempotency_key].empty?)
88
+ if @verb.downcase == "post" && !@options[:idempotency_key].nil? && !@options[:idempotency_key].empty?
83
89
  @headers["Idempotency-Key"] = @options[:idempotency_key]
84
90
  end
85
91
  end
@@ -101,5 +107,12 @@ module Resend
101
107
  rescue JSON::ParserError, TypeError
102
108
  raise Resend::Error::InternalServerError.new("Resend API returned an unexpected response", nil)
103
109
  end
110
+
111
+ # Extract and normalize headers from the HTTParty response
112
+ def extract_headers(resp)
113
+ return {} unless resp.respond_to?(:headers)
114
+
115
+ resp.headers.to_h.transform_keys { |k| k.to_s.downcase }
116
+ end
104
117
  end
105
118
  end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Resend
4
+ # Response wrapper that maintains backwards compatibility while exposing headers
5
+ #
6
+ # This class wraps API responses and behaves like a Hash for backwards compatibility,
7
+ # while also providing access to response headers via the #headers method.
8
+ #
9
+ # @example Backwards compatible hash access
10
+ # response = Resend::Emails.send(params)
11
+ # response[:id] # => "49a3999c-0ce1-4ea6-ab68-afcd6dc2e794"
12
+ #
13
+ # @example Accessing response headers
14
+ # response = Resend::Emails.send(params)
15
+ # response.headers # => {"content-type" => "application/json", ...}
16
+ # response.headers['x-ratelimit-remaining'] # => "50"
17
+ class Response
18
+ include Enumerable
19
+
20
+ # @param data [Hash] The response data
21
+ # @param headers [Hash, HTTParty::Response] The response headers
22
+ def initialize(data, headers)
23
+ @data = data.is_a?(Hash) ? data : {}
24
+ @headers = normalize_headers(headers)
25
+ end
26
+
27
+ # Access response headers
28
+ # @return [Hash] Response headers as a hash with lowercase string keys
29
+ attr_reader :headers
30
+
31
+ # Hash-like access via []
32
+ # @param key [Symbol, String] The key to access
33
+ # @return [Object] The value at the key
34
+ def [](key)
35
+ @data[key]
36
+ end
37
+
38
+ # Hash-like assignment via []=
39
+ # @param key [Symbol, String] The key to set
40
+ # @param value [Object] The value to set
41
+ def []=(key, value)
42
+ @data[key] = value
43
+ end
44
+
45
+ # Dig into nested hash structure
46
+ # @param keys [Array<Symbol, String>] Keys to dig through
47
+ # @return [Object] The value at the nested key path
48
+ def dig(*keys)
49
+ @data.dig(*keys)
50
+ end
51
+
52
+ # Convert to plain hash
53
+ # @return [Hash] The underlying data hash
54
+ def to_h
55
+ @data
56
+ end
57
+
58
+ alias to_hash to_h
59
+
60
+ # Get all keys from the data
61
+ # @return [Array] Array of keys
62
+ def keys
63
+ @data.keys
64
+ end
65
+
66
+ # Get all values from the data
67
+ # @return [Array] Array of values
68
+ def values
69
+ @data.values
70
+ end
71
+
72
+ # Check if key exists
73
+ # @param key [Symbol, String] The key to check
74
+ # @return [Boolean] True if key exists
75
+ def key?(key)
76
+ @data.key?(key)
77
+ end
78
+
79
+ alias has_key? key?
80
+
81
+ # Enable enumeration over the data
82
+ def each(&block)
83
+ @data.each(&block)
84
+ end
85
+
86
+ # Transform keys in the underlying data
87
+ # @return [Resend::Response] Self for chaining
88
+ def transform_keys!(&block)
89
+ @data.transform_keys!(&block)
90
+ self
91
+ end
92
+
93
+ # Check if response is empty
94
+ # @return [Boolean] True if data is empty
95
+ def empty?
96
+ @data.empty?
97
+ end
98
+
99
+ # Respond to hash-like methods
100
+ def respond_to_missing?(method_name, include_private = false)
101
+ @data.respond_to?(method_name) || super
102
+ end
103
+
104
+ # Delegate unknown methods to the underlying data hash
105
+ def method_missing(method_name, *args, &block)
106
+ if @data.respond_to?(method_name)
107
+ result = @data.send(method_name, *args, &block)
108
+ # If the method returns the hash itself, return self to maintain wrapper
109
+ result.equal?(@data) ? self : result
110
+ else
111
+ super
112
+ end
113
+ end
114
+
115
+ # String representation for debugging
116
+ # @return [String] String representation of the response
117
+ def inspect
118
+ "#<Resend::Response data=#{@data.inspect} headers=#{@headers.keys.inspect}>"
119
+ end
120
+
121
+ private
122
+
123
+ # Normalize headers to a simple hash with lowercase string keys
124
+ # @param headers [Hash, HTTParty::Response, nil] The headers to normalize
125
+ # @return [Hash] Normalized headers hash
126
+ def normalize_headers(headers)
127
+ return {} if headers.nil?
128
+
129
+ # Handle HTTParty::Response object
130
+ headers = headers.headers if headers.respond_to?(:headers)
131
+
132
+ # Convert to hash and normalize keys to lowercase strings
133
+ case headers
134
+ when Hash
135
+ headers.to_h.transform_keys { |k| k.to_s.downcase }
136
+ else
137
+ {}
138
+ end
139
+ end
140
+ end
141
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Resend
4
- VERSION = "1.0.0"
4
+ VERSION = "1.0.1"
5
5
  end
data/lib/resend.rb CHANGED
@@ -8,6 +8,7 @@ require "httparty"
8
8
  require "json"
9
9
  require "cgi"
10
10
  require "resend/errors"
11
+ require "resend/response"
11
12
  require "resend/client"
12
13
  require "resend/request"
13
14
  require "resend/pagination_helper"
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: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Derich Pacheco
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-10-31 00:00:00.000000000 Z
11
+ date: 2026-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -38,7 +38,7 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
- description:
41
+ description:
42
42
  email: carlosderich@gmail.com
43
43
  executables: []
44
44
  extensions: []
@@ -65,6 +65,7 @@ files:
65
65
  - lib/resend/pagination_helper.rb
66
66
  - lib/resend/railtie.rb
67
67
  - lib/resend/request.rb
68
+ - lib/resend/response.rb
68
69
  - lib/resend/segments.rb
69
70
  - lib/resend/templates.rb
70
71
  - lib/resend/topics.rb
@@ -74,7 +75,7 @@ homepage: https://github.com/resend/resend-ruby
74
75
  licenses:
75
76
  - MIT
76
77
  metadata: {}
77
- post_install_message:
78
+ post_install_message:
78
79
  rdoc_options: []
79
80
  require_paths:
80
81
  - lib
@@ -89,8 +90,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
90
  - !ruby/object:Gem::Version
90
91
  version: '0'
91
92
  requirements: []
92
- rubygems_version: 3.4.10
93
- signing_key:
93
+ rubygems_version: 3.0.3.1
94
+ signing_key:
94
95
  specification_version: 4
95
96
  summary: The Ruby and Rails SDK for resend.com
96
97
  test_files: []