nylas 6.5.0 → 6.6.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: f9529fffa30430e822edf113d38aa1a179f0995b29d2bec8c3ac5f9a26d4d8c7
4
- data.tar.gz: 8710b98962a46bef277461df24f5e64dedd9bdbe7949838b2b3d8aab38b36f10
3
+ metadata.gz: b88e46de5b92ca56b82971334bc996b373407c76612b7ae7cf560a6496c5fb57
4
+ data.tar.gz: 25caea97521efd4fd2f903eed63b375b91a47142c797fd109cb60169a4d51920
5
5
  SHA512:
6
- metadata.gz: 20e35b192df7f3dfaf0d50065556d3ef0c19e959504dc124ec3bd2a6f657ffebb7a61b4808517494b2d79d4ceccdd8ce88e45d49109c142ad366592481a67b56
7
- data.tar.gz: d957251f63c3c8aa8b90adde51ba2ea7fe52be3b08ca8017e1b91a22c4e42c4d428a720c1b3a18191d1861d2bf379ebd93e481b30547ffbe4ce8f99578e85fb1
6
+ metadata.gz: 4af7e805753ad3df593249379933f58cfc42b25c962fafbfae041554d87fe66d59dd4ee1b18475bcf0c69e65dcfe57f1a384d9e9289e9c74fbda20b92d568fb6
7
+ data.tar.gz: 704f122a8273212641bcb02c4b1dd6b225d00f64f23655cd3c35ec81d654e1c1e6585d44a99a7caf7a991f4ee8f3fc6f05c61008cc1496b4c2f5fc5521ee9c28
@@ -103,6 +103,7 @@ module Nylas
103
103
  is_multipart = !payload.nil? && (payload["multipart"] || payload[:multipart])
104
104
 
105
105
  if !payload.nil? && !is_multipart
106
+ normalize_json_encodings!(payload)
106
107
  payload = payload&.to_json
107
108
  resulting_headers["Content-type"] = "application/json"
108
109
  elsif is_multipart
@@ -149,7 +150,7 @@ module Nylas
149
150
  # Handle multipart uploads
150
151
  if payload.is_a?(Hash) && file_upload?(payload)
151
152
  options[:multipart] = true
152
- options[:body] = payload
153
+ options[:body] = prepare_multipart_payload(payload)
153
154
  elsif payload
154
155
  options[:body] = payload
155
156
  end
@@ -176,9 +177,113 @@ module Nylas
176
177
  def file_upload?(payload)
177
178
  return false unless payload.is_a?(Hash)
178
179
 
179
- payload.values.any? do |value|
180
+ # Check for traditional file uploads (File objects or objects that respond to :read)
181
+ has_file_objects = payload.values.any? do |value|
180
182
  value.respond_to?(:read) || (value.is_a?(File) && !value.closed?)
181
183
  end
184
+
185
+ return true if has_file_objects
186
+
187
+ # Check if payload was prepared by FileUtils.build_form_request for multipart uploads
188
+ # This handles binary content attachments that are strings with added singleton methods
189
+ has_message_field = payload.key?("message") && payload["message"].is_a?(String)
190
+ has_attachment_fields = payload.keys.any? { |key| key.is_a?(String) && key.match?(/^file\d+$/) }
191
+
192
+ # If we have both a "message" field and "file{N}" fields, this indicates
193
+ # the payload was prepared by FileUtils.build_form_request for multipart upload
194
+ has_message_field && has_attachment_fields
195
+ end
196
+
197
+ # Prepare multipart payload for HTTParty compatibility
198
+ # HTTParty requires all multipart fields to have compatible encodings
199
+ def prepare_multipart_payload(payload)
200
+ require "stringio"
201
+
202
+ modified_payload = payload.dup
203
+
204
+ # First, normalize all string encodings to prevent HTTParty encoding conflicts
205
+ normalize_multipart_encodings!(modified_payload)
206
+
207
+ # Handle binary content attachments (file0, file1, etc.) by converting them to enhanced StringIO
208
+ # HTTParty expects file uploads to be objects with full file-like interface
209
+ modified_payload.each do |key, value|
210
+ next unless key.is_a?(String) && key.match?(/^file\d+$/) && value.is_a?(String)
211
+
212
+ # Get the original value to check for singleton methods
213
+ original_value = payload[key]
214
+
215
+ # Create an enhanced StringIO object for HTTParty compatibility
216
+ string_io = create_file_like_stringio(value)
217
+
218
+ # Preserve filename and content_type if they exist as singleton methods
219
+ if original_value.respond_to?(:original_filename)
220
+ string_io.define_singleton_method(:original_filename) { original_value.original_filename }
221
+ end
222
+
223
+ if original_value.respond_to?(:content_type)
224
+ string_io.define_singleton_method(:content_type) { original_value.content_type }
225
+ end
226
+
227
+ modified_payload[key] = string_io
228
+ end
229
+
230
+ modified_payload
231
+ end
232
+
233
+ # Normalize string encodings in multipart payload to prevent HTTParty encoding conflicts
234
+ # This ensures all string fields use consistent ASCII-8BIT encoding for multipart compatibility
235
+ def normalize_multipart_encodings!(payload)
236
+ payload.each do |key, value|
237
+ next unless value.is_a?(String)
238
+
239
+ # Force all string values to ASCII-8BIT encoding for multipart compatibility
240
+ # HTTParty/multipart-post expects binary encoding for consistent concatenation
241
+ payload[key] = value.dup.force_encoding(Encoding::ASCII_8BIT)
242
+ end
243
+ end
244
+
245
+ # Normalize JSON encodings for attachment content to ensure binary data is base64 encoded.
246
+ # This handles cases where users pass raw binary content directly instead of file objects.
247
+ def normalize_json_encodings!(payload)
248
+ return unless payload.is_a?(Hash)
249
+
250
+ # Handle attachment content encoding for JSON serialization
251
+ attachments = payload[:attachments] || payload["attachments"]
252
+ return unless attachments
253
+
254
+ attachments.each do |attachment|
255
+ content = attachment[:content] || attachment["content"]
256
+ next unless content.is_a?(String)
257
+
258
+ # If content appears to be binary (non-UTF-8), base64 encode it
259
+ next unless content.encoding == Encoding::ASCII_8BIT || !content.valid_encoding?
260
+
261
+ encoded_content = Base64.strict_encode64(content)
262
+ if attachment.key?(:content)
263
+ attachment[:content] = encoded_content
264
+ else
265
+ attachment["content"] = encoded_content
266
+ end
267
+ end
268
+ end
269
+
270
+ # Create a StringIO object that behaves more like a File for HTTParty compatibility
271
+ def create_file_like_stringio(content)
272
+ # Content is already normalized to ASCII-8BIT by normalize_multipart_encodings!
273
+ # Create StringIO with the normalized binary content
274
+ string_io = StringIO.new(content)
275
+
276
+ # Add methods that HTTParty/multipart-post might expect
277
+ string_io.define_singleton_method(:path) { nil }
278
+ string_io.define_singleton_method(:local_path) { nil }
279
+ string_io.define_singleton_method(:respond_to_missing?) do |method_name, include_private = false|
280
+ File.instance_methods.include?(method_name) || super(method_name, include_private)
281
+ end
282
+
283
+ # Set binary mode for file-like behavior
284
+ string_io.binmode if string_io.respond_to?(:binmode)
285
+
286
+ string_io
182
287
  end
183
288
 
184
289
  def setup_http(path, timeout, headers, query, api_key)
@@ -15,6 +15,11 @@ module Nylas
15
15
  #
16
16
  # @param identifier [String] Grant ID or email account to query.
17
17
  # @param query_params [Hash, nil] Query params to pass to the request.
18
+ # Supported parameters include:
19
+ # - single_level: (Boolean) For Microsoft accounts only. If true, retrieves folders from
20
+ # a single-level hierarchy only. If false (default), retrieves folders across a
21
+ # multi-level hierarchy.
22
+ # - include_hidden_folders [Boolean] (Microsoft only) When true, includes hidden folders.
18
23
  # @return [Array(Array(Hash), String, String)] The list of folders, API Request ID, and next cursor.
19
24
  def list(identifier:, query_params: nil)
20
25
  get_list(
@@ -126,7 +126,7 @@ module Nylas
126
126
  request_body: payload
127
127
  )
128
128
 
129
- opened_files.each(&:close)
129
+ opened_files.each { |file| file.close if file.respond_to?(:close) }
130
130
 
131
131
  response
132
132
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "cgi"
3
4
  require_relative "resource"
4
5
  require_relative "../handler/api_operations"
5
6
 
data/lib/nylas/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nylas
4
- VERSION = "6.5.0"
4
+ VERSION = "6.6.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nylas
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.5.0
4
+ version: 6.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nylas, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-06-13 00:00:00.000000000 Z
11
+ date: 2025-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64