x 0.17.0 → 0.19.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/README.md +17 -4
  4. data/lib/x/account_uploader.rb +168 -0
  5. data/lib/x/authenticator.rb +12 -0
  6. data/lib/x/bearer_token_authenticator.rb +22 -1
  7. data/lib/x/client.rb +121 -52
  8. data/lib/x/client_credentials.rb +208 -0
  9. data/lib/x/connection.rb +107 -4
  10. data/lib/x/errors/bad_gateway.rb +1 -0
  11. data/lib/x/errors/bad_request.rb +1 -0
  12. data/lib/x/errors/client_error.rb +1 -0
  13. data/lib/x/errors/connection_exception.rb +1 -0
  14. data/lib/x/errors/error.rb +1 -0
  15. data/lib/x/errors/forbidden.rb +1 -0
  16. data/lib/x/errors/gateway_timeout.rb +1 -0
  17. data/lib/x/errors/gone.rb +1 -0
  18. data/lib/x/errors/http_error.rb +47 -4
  19. data/lib/x/errors/internal_server_error.rb +1 -0
  20. data/lib/x/errors/invalid_media_type.rb +6 -0
  21. data/lib/x/errors/network_error.rb +1 -0
  22. data/lib/x/errors/not_acceptable.rb +1 -0
  23. data/lib/x/errors/not_found.rb +1 -0
  24. data/lib/x/errors/payload_too_large.rb +1 -0
  25. data/lib/x/errors/server_error.rb +1 -0
  26. data/lib/x/errors/service_unavailable.rb +1 -0
  27. data/lib/x/errors/too_many_redirects.rb +1 -0
  28. data/lib/x/errors/too_many_requests.rb +32 -0
  29. data/lib/x/errors/unauthorized.rb +1 -0
  30. data/lib/x/errors/unprocessable_entity.rb +1 -0
  31. data/lib/x/media_upload_validator.rb +19 -0
  32. data/lib/x/media_uploader.rb +117 -5
  33. data/lib/x/oauth2_authenticator.rb +169 -0
  34. data/lib/x/oauth_authenticator.rb +99 -2
  35. data/lib/x/rate_limit.rb +57 -1
  36. data/lib/x/redirect_handler.rb +55 -1
  37. data/lib/x/request_builder.rb +36 -0
  38. data/lib/x/response_parser.rb +21 -0
  39. data/lib/x/stream_parser.rb +75 -0
  40. data/lib/x/version.rb +2 -1
  41. data/sig/x.rbs +94 -18
  42. metadata +7 -2
@@ -6,12 +6,42 @@ require_relative "errors/too_many_redirects"
6
6
  require_relative "request_builder"
7
7
 
8
8
  module X
9
+ # Handles HTTP redirects for API requests
10
+ # @api public
9
11
  class RedirectHandler
12
+ # Default maximum number of redirects to follow
10
13
  DEFAULT_MAX_REDIRECTS = 10
11
14
 
15
+ # The maximum number of redirects to follow
16
+ # @api public
17
+ # @return [Integer] the maximum number of redirects to follow
18
+ # @example Get or set the maximum redirects
19
+ # handler.max_redirects = 5
12
20
  attr_accessor :max_redirects
13
- attr_reader :connection, :request_builder
14
21
 
22
+ # The connection for making requests
23
+ # @api public
24
+ # @return [Connection] the connection for making requests
25
+ # @example Get the connection
26
+ # handler.connection
27
+ attr_reader :connection
28
+
29
+ # The request builder for creating requests
30
+ # @api public
31
+ # @return [RequestBuilder] the request builder for creating requests
32
+ # @example Get the request builder
33
+ # handler.request_builder
34
+ attr_reader :request_builder
35
+
36
+ # Initialize a new RedirectHandler
37
+ #
38
+ # @api public
39
+ # @param connection [Connection] the connection for making requests
40
+ # @param request_builder [RequestBuilder] the request builder for creating requests
41
+ # @param max_redirects [Integer] the maximum number of redirects to follow
42
+ # @return [RedirectHandler] a new instance
43
+ # @example Create a redirect handler
44
+ # handler = X::RedirectHandler.new(connection: conn, request_builder: builder)
15
45
  def initialize(connection: Connection.new, request_builder: RequestBuilder.new,
16
46
  max_redirects: DEFAULT_MAX_REDIRECTS)
17
47
  @connection = connection
@@ -19,6 +49,18 @@ module X
19
49
  @max_redirects = max_redirects
20
50
  end
21
51
 
52
+ # Handle redirects for an HTTP response
53
+ #
54
+ # @api public
55
+ # @param response [Net::HTTPResponse] the HTTP response to handle
56
+ # @param request [Net::HTTPRequest] the original HTTP request
57
+ # @param base_url [String] the base URL for the request
58
+ # @param authenticator [Authenticator] the authenticator for requests
59
+ # @param redirect_count [Integer] the current redirect count
60
+ # @return [Net::HTTPResponse] the final HTTP response after following redirects
61
+ # @raise [TooManyRedirects] if the maximum number of redirects is exceeded
62
+ # @example Handle a response
63
+ # response = handler.handle(response: resp, request: req, base_url: url)
22
64
  def handle(response:, request:, base_url:, authenticator: Authenticator.new, redirect_count: 0)
23
65
  if response.is_a?(Net::HTTPRedirection)
24
66
  raise TooManyRedirects, "Too many redirects" if redirect_count > max_redirects
@@ -36,12 +78,24 @@ module X
36
78
 
37
79
  private
38
80
 
81
+ # Build a new URI from the redirect response
82
+ # @api private
83
+ # @param response [Net::HTTPResponse] the redirect response
84
+ # @param base_url [String] the base URL
85
+ # @return [URI] the new URI
39
86
  def build_new_uri(response, base_url)
40
87
  location = response.fetch("location")
41
88
  # If location is relative, it will join with the original base URL, otherwise it will overwrite it
42
89
  URI.join(base_url, location)
43
90
  end
44
91
 
92
+ # Build a new request for the redirect
93
+ # @api private
94
+ # @param request [Net::HTTPRequest] the original request
95
+ # @param uri [URI] the new URI
96
+ # @param response_code [Integer] the HTTP response code
97
+ # @param authenticator [Authenticator] the authenticator
98
+ # @return [Net::HTTPRequest] the new request
45
99
  def build_request(request, uri, response_code, authenticator)
46
100
  http_method = :get
47
101
  if [307, 308].include?(response_code)
@@ -4,11 +4,15 @@ require_relative "authenticator"
4
4
  require_relative "version"
5
5
 
6
6
  module X
7
+ # Builds HTTP requests for the X API
8
+ # @api public
7
9
  class RequestBuilder
10
+ # Default headers for API requests
8
11
  DEFAULT_HEADERS = {
9
12
  "Content-Type" => "application/json; charset=utf-8",
10
13
  "User-Agent" => "X-Client/#{VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION} (#{RUBY_PLATFORM})"
11
14
  }.freeze
15
+ # Mapping of HTTP method symbols to Net::HTTP classes
12
16
  HTTP_METHODS = {
13
17
  get: Net::HTTP::Get,
14
18
  post: Net::HTTP::Post,
@@ -16,6 +20,18 @@ module X
16
20
  delete: Net::HTTP::Delete
17
21
  }.freeze
18
22
 
23
+ # Build an HTTP request
24
+ #
25
+ # @api public
26
+ # @param http_method [Symbol] the HTTP method (:get, :post, :put, :delete)
27
+ # @param uri [URI] the request URI
28
+ # @param body [String, nil] the request body
29
+ # @param headers [Hash] additional headers for the request
30
+ # @param authenticator [Authenticator] the authenticator for the request
31
+ # @return [Net::HTTPRequest] the built HTTP request
32
+ # @raise [ArgumentError] if the HTTP method is not supported
33
+ # @example Build a GET request
34
+ # builder.build(http_method: :get, uri: URI("https://api.x.com/2/users/me"))
19
35
  def build(http_method:, uri:, body: nil, headers: {}, authenticator: Authenticator.new)
20
36
  request = create_request(http_method:, uri:, body:)
21
37
  add_headers(request:, headers:)
@@ -25,6 +41,12 @@ module X
25
41
 
26
42
  private
27
43
 
44
+ # Create an HTTP request
45
+ # @api private
46
+ # @param http_method [Symbol] the HTTP method
47
+ # @param uri [URI] the request URI
48
+ # @param body [String, nil] the request body
49
+ # @return [Net::HTTPRequest] the created request
28
50
  def create_request(http_method:, uri:, body:)
29
51
  http_method_class = HTTP_METHODS[http_method]
30
52
 
@@ -36,18 +58,32 @@ module X
36
58
  request
37
59
  end
38
60
 
61
+ # Add authentication to a request
62
+ # @api private
63
+ # @param request [Net::HTTPRequest] the request
64
+ # @param authenticator [Authenticator] the authenticator
65
+ # @return [void]
39
66
  def add_authentication(request:, authenticator:)
40
67
  authenticator.header(request).each do |key, value|
41
68
  request[key] = value
42
69
  end
43
70
  end
44
71
 
72
+ # Add headers to a request
73
+ # @api private
74
+ # @param request [Net::HTTPRequest] the request
75
+ # @param headers [Hash] additional headers
76
+ # @return [void]
45
77
  def add_headers(request:, headers:)
46
78
  DEFAULT_HEADERS.merge(headers).each do |key, value|
47
79
  request[key] = value
48
80
  end
49
81
  end
50
82
 
83
+ # Escape query parameters in a URI
84
+ # @api private
85
+ # @param uri [URI] the URI
86
+ # @return [URI] the URI with escaped query parameters
51
87
  def escape_query_params(uri)
52
88
  URI(uri).tap do |u|
53
89
  u.query = URI.encode_www_form(URI.decode_www_form(u.query)).gsub("%2C", ",") if u.query
@@ -17,7 +17,10 @@ require_relative "errors/unauthorized"
17
17
  require_relative "errors/unprocessable_entity"
18
18
 
19
19
  module X
20
+ # Parses HTTP responses from the X API
21
+ # @api public
20
22
  class ResponseParser
23
+ # Mapping of HTTP status codes to error classes
21
24
  ERROR_MAP = {
22
25
  400 => BadRequest,
23
26
  401 => Unauthorized,
@@ -35,6 +38,16 @@ module X
35
38
  504 => GatewayTimeout
36
39
  }.freeze
37
40
 
41
+ # Parse an HTTP response
42
+ #
43
+ # @api public
44
+ # @param response [Net::HTTPResponse] the HTTP response to parse
45
+ # @param array_class [Class, nil] the class for parsing JSON arrays
46
+ # @param object_class [Class, nil] the class for parsing JSON objects
47
+ # @return [Hash, Array, nil] the parsed response body
48
+ # @raise [HTTPError] if the response is not successful
49
+ # @example Parse a response
50
+ # parser.parse(response: response)
38
51
  def parse(response:, array_class: nil, object_class: nil)
39
52
  raise error(response) unless response.is_a?(Net::HTTPSuccess)
40
53
 
@@ -49,10 +62,18 @@ module X
49
62
 
50
63
  private
51
64
 
65
+ # Create an error from a response
66
+ # @api private
67
+ # @param response [Net::HTTPResponse] the HTTP response
68
+ # @return [HTTPError] the error
52
69
  def error(response)
53
70
  error_class(response).new(response:)
54
71
  end
55
72
 
73
+ # Get the error class for a response
74
+ # @api private
75
+ # @param response [Net::HTTPResponse] the HTTP response
76
+ # @return [Class] the error class
56
77
  def error_class(response)
57
78
  ERROR_MAP[Integer(response.code)] || HTTPError
58
79
  end
@@ -0,0 +1,75 @@
1
+ require "json"
2
+ require "net/http"
3
+ require_relative "response_parser"
4
+
5
+ module X
6
+ # Handles streaming responses from the X API
7
+ # @api public
8
+ class StreamParser
9
+ # Line delimiter for streaming responses
10
+ LINE_DELIMITER = "\r\n".freeze
11
+
12
+ # Process a streaming response and yield parsed JSON objects
13
+ #
14
+ # @api public
15
+ # @param response [Net::HTTPResponse] the HTTP response to stream
16
+ # @param response_parser [ResponseParser] the response parser for error handling
17
+ # @param array_class [Class, nil] the class for parsing JSON arrays
18
+ # @param object_class [Class, nil] the class for parsing JSON objects
19
+ # @yield [Hash, Array] each parsed JSON object from the stream
20
+ # @return [void]
21
+ # @raise [HTTPError] if the response is not successful
22
+ # @example Process a streaming response
23
+ # handler.process(response: response, response_parser: parser) { |json| puts json }
24
+ def process(response:, response_parser:, array_class: nil, object_class: nil, &block)
25
+ response_parser.parse(response:) unless response.is_a?(Net::HTTPSuccess)
26
+
27
+ buffer = +""
28
+ response.read_body do |chunk|
29
+ buffer << chunk
30
+ process_buffer(buffer:, array_class:, object_class:, &block)
31
+ end
32
+ process_remaining(buffer:, array_class:, object_class:, &block)
33
+ end
34
+
35
+ private
36
+
37
+ # Process complete lines from the buffer
38
+ # @api private
39
+ # @param buffer [String] the accumulated data buffer
40
+ # @param array_class [Class, nil] the class for parsing JSON arrays
41
+ # @param object_class [Class, nil] the class for parsing JSON objects
42
+ # @yield [Hash, Array] each parsed JSON object
43
+ # @return [void]
44
+ def process_buffer(buffer:, array_class:, object_class:, &)
45
+ while (line_end = buffer.index(LINE_DELIMITER))
46
+ line = buffer.slice!(0, line_end) # : String
47
+ buffer.delete_prefix!(LINE_DELIMITER)
48
+ yield_json(line:, array_class:, object_class:, &) unless line.empty?
49
+ end
50
+ end
51
+
52
+ # Process any remaining data after the stream ends
53
+ # @api private
54
+ # @param buffer [String] the remaining data buffer
55
+ # @param array_class [Class, nil] the class for parsing JSON arrays
56
+ # @param object_class [Class, nil] the class for parsing JSON objects
57
+ # @yield [Hash, Array] the parsed JSON object
58
+ # @return [void]
59
+ def process_remaining(buffer:, array_class:, object_class:, &)
60
+ buffer.strip!
61
+ yield_json(line: buffer, array_class:, object_class:, &) unless buffer.empty?
62
+ end
63
+
64
+ # Parse a line as JSON and yield the result
65
+ # @api private
66
+ # @param line [String] the JSON line to parse
67
+ # @param array_class [Class, nil] the class for parsing JSON arrays
68
+ # @param object_class [Class, nil] the class for parsing JSON objects
69
+ # @yield [Hash, Array] the parsed JSON object
70
+ # @return [void]
71
+ def yield_json(line:, array_class:, object_class:)
72
+ yield JSON.parse(line, array_class:, object_class:)
73
+ end
74
+ end
75
+ end
data/lib/x/version.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "rubygems/version"
2
2
 
3
3
  module X
4
- VERSION = Gem::Version.create("0.17.0")
4
+ # The current version of the X gem
5
+ VERSION = Gem::Version.create("0.19.0")
5
6
  end
data/sig/x.rbs CHANGED
@@ -101,6 +101,9 @@ module X
101
101
  class TooManyRedirects < Error
102
102
  end
103
103
 
104
+ class InvalidMediaType < Error
105
+ end
106
+
104
107
  class TooManyRequests < ClientError
105
108
  @rate_limits: Array[RateLimit]
106
109
 
@@ -122,7 +125,7 @@ module X
122
125
  DEFAULT_OPEN_TIMEOUT: Integer
123
126
  DEFAULT_READ_TIMEOUT: Integer
124
127
  DEFAULT_WRITE_TIMEOUT: Integer
125
- DEFAULT_DEBUG_OUTPUT: IO
128
+
126
129
  NETWORK_ERRORS: Array[(singleton(Errno::ECONNREFUSED) | singleton(Errno::ECONNRESET) | singleton(Net::OpenTimeout) | singleton(Net::ReadTimeout) | singleton(OpenSSL::SSL::SSLError))]
127
130
 
128
131
  @proxy_url: URI::Generic | String
@@ -143,6 +146,7 @@ module X
143
146
  def initialize: (?open_timeout: Float | Integer, ?read_timeout: Float | Integer, ?write_timeout: Float | Integer, ?proxy_url: URI::Generic? | String?, ?debug_output: IO) -> void
144
147
  def proxy_url=: (URI::Generic | String proxy_url) -> void
145
148
  def perform: (request: Net::HTTPRequest) -> Net::HTTPResponse
149
+ def perform_stream: (request: Net::HTTPRequest) { (Net::HTTPResponse) -> void } -> void
146
150
 
147
151
  private
148
152
  def build_http_client: (?String host, ?Integer port) -> Net::HTTP
@@ -205,40 +209,94 @@ module X
205
209
  def json?: (Net::HTTPResponse response) -> bool
206
210
  end
207
211
 
212
+ class StreamParser
213
+ LINE_DELIMITER: String
214
+
215
+ def process: (response: Net::HTTPResponse, response_parser: ResponseParser, ?array_class: Class?, ?object_class: Class?) { (untyped) -> void } -> void
216
+
217
+ private
218
+ def process_buffer: (buffer: String, array_class: Class?, object_class: Class?) { (untyped) -> void } -> void
219
+ def process_remaining: (buffer: String, array_class: Class?, object_class: Class?) { (untyped) -> void } -> void
220
+ def yield_json: (line: String, array_class: Class?, object_class: Class?) { (untyped) -> void } -> void
221
+ end
222
+
223
+ class OAuth2Authenticator < Authenticator
224
+ TOKEN_PATH: String
225
+ TOKEN_HOST: String
226
+ REFRESH_GRANT_TYPE: String
227
+ EXPIRATION_BUFFER: Integer
228
+
229
+ attr_accessor client_id: String
230
+ attr_accessor client_secret: String
231
+ attr_accessor access_token: String
232
+ attr_accessor refresh_token: String
233
+ attr_accessor expires_at: Time?
234
+ attr_accessor connection: Connection
235
+ def initialize: (client_id: String, client_secret: String, access_token: String, refresh_token: String, ?expires_at: Time?, ?connection: Connection) -> void
236
+ def header: (Net::HTTPRequest? request) -> Hash[String, String]
237
+ def token_expired?: -> bool
238
+ def refresh_token!: -> Hash[String, untyped]
239
+
240
+ private
241
+ def send_token_request: -> Net::HTTPResponse
242
+ def build_token_request: -> Net::HTTP::Post
243
+ def handle_token_response: (Net::HTTPResponse response) -> Hash[String, untyped]
244
+ def update_tokens: (Hash[String, untyped] token_response) -> void
245
+ end
246
+
247
+ module ClientCredentials
248
+ attr_reader api_key: String?
249
+ attr_reader api_key_secret: String?
250
+ attr_reader access_token: String?
251
+ attr_reader access_token_secret: String?
252
+ attr_reader bearer_token: String?
253
+ attr_reader client_id: String?
254
+ attr_reader client_secret: String?
255
+ attr_reader refresh_token: String?
256
+ def api_key=: (String api_key) -> void
257
+ def api_key_secret=: (String api_key_secret) -> void
258
+ def access_token=: (String access_token) -> void
259
+ def access_token_secret=: (String access_token_secret) -> void
260
+ def bearer_token=: (String bearer_token) -> void
261
+ def client_id=: (String client_id) -> void
262
+ def client_secret=: (String client_secret) -> void
263
+ def refresh_token=: (String refresh_token) -> void
264
+
265
+ private
266
+ def initialize_credentials: (api_key: String?, api_key_secret: String?, access_token: String?, access_token_secret: String?, bearer_token: String?, client_id: String?, client_secret: String?, refresh_token: String?) -> void
267
+ def initialize_authenticator: -> (Authenticator | BearerTokenAuthenticator | OAuthAuthenticator | OAuth2Authenticator)
268
+ def oauth_authenticator: -> OAuthAuthenticator?
269
+ def oauth2_authenticator: -> OAuth2Authenticator?
270
+ def bearer_authenticator: -> BearerTokenAuthenticator?
271
+ end
272
+
208
273
  class Client
274
+ include ClientCredentials
275
+
209
276
  DEFAULT_BASE_URL: String
210
277
  DEFAULT_ARRAY_CLASS: singleton(Array)
211
278
  DEFAULT_OBJECT_CLASS: singleton(Hash)
212
279
  extend Forwardable
213
- @authenticator: Authenticator | BearerTokenAuthenticator | OAuthAuthenticator
280
+ @authenticator: Authenticator | BearerTokenAuthenticator | OAuthAuthenticator | OAuth2Authenticator
214
281
  @connection: Connection
215
282
  @request_builder: RequestBuilder
216
283
  @redirect_handler: RedirectHandler
217
284
  @response_parser: ResponseParser
285
+ @stream_parser: StreamParser
218
286
 
219
287
  attr_accessor base_url: String
220
288
  attr_accessor default_array_class: singleton(Array)
221
289
  attr_accessor default_object_class: singleton(Hash)
222
- attr_reader api_key: String?
223
- attr_reader api_key_secret: String?
224
- attr_reader access_token: String?
225
- attr_reader access_token_secret: String?
226
- attr_reader bearer_token: String?
227
- def initialize: (?api_key: nil, ?api_key_secret: nil, ?access_token: nil, ?access_token_secret: nil, ?bearer_token: nil, ?base_url: String, ?open_timeout: Integer, ?read_timeout: Integer, ?write_timeout: Integer, ?debug_output: untyped, ?proxy_url: nil, ?default_array_class: singleton(Array), ?default_object_class: singleton(Hash), ?max_redirects: Integer) -> void
290
+ attr_reader authenticator: Authenticator | BearerTokenAuthenticator | OAuthAuthenticator | OAuth2Authenticator
291
+ def initialize: (?api_key: String?, ?api_key_secret: String?, ?access_token: String?, ?access_token_secret: String?, ?bearer_token: String?, ?client_id: String?, ?client_secret: String?, ?refresh_token: String?, ?base_url: String, ?open_timeout: Integer, ?read_timeout: Integer, ?write_timeout: Integer, ?debug_output: untyped, ?proxy_url: String?, ?default_array_class: singleton(Array), ?default_object_class: singleton(Hash), ?max_redirects: Integer) -> void
228
292
  def get: (String endpoint, ?headers: Hash[String, String], ?array_class: Class, ?object_class: Class) -> untyped
229
293
  def post: (String endpoint, ?String? body, ?headers: Hash[String, String], ?array_class: Class, ?object_class: Class) -> untyped
230
294
  def put: (String endpoint, ?String? body, ?headers: Hash[String, String], ?array_class: Class, ?object_class: Class) -> untyped
231
295
  def delete: (String endpoint, ?headers: Hash[String, String], ?array_class: Class, ?object_class: Class) -> untyped
232
- def api_key=: (String api_key) -> void
233
- def api_key_secret=: (String api_key_secret) -> void
234
- def access_token=: (String access_token) -> void
235
- def access_token_secret=: (String access_token_secret) -> void
236
- def bearer_token=: (String bearer_token) -> void
296
+ def stream: (String endpoint, ?headers: Hash[String, String], ?array_class: Class, ?object_class: Class) { (untyped) -> void } -> void
237
297
 
238
298
  private
239
- def initialize_oauth: (String? api_key, String? api_key_secret, String? access_token, String? access_token_secret, String? bearer_token) -> void
240
- def initialize_default_classes: (singleton(Array) default_array_class, singleton(Hash) default_object_class) -> singleton(Hash)
241
- def initialize_authenticator: -> (Authenticator | BearerTokenAuthenticator | OAuthAuthenticator)
299
+ def initialize_default_classes: (default_array_class: singleton(Array), default_object_class: singleton(Hash)) -> void
242
300
  def execute_request: (:delete | :get | :post | :put http_method, String endpoint, ?body: String?, ?headers: Hash[String, String], ?array_class: Class, ?object_class: Class) -> nil
243
301
  end
244
302
 
@@ -252,7 +310,6 @@ module X
252
310
  TWEET_GIF: String
253
311
  TWEET_IMAGE: String
254
312
  TWEET_VIDEO: String
255
- DEFAULT_MIME_TYPE: String
256
313
  MIME_TYPES: Array[String]
257
314
  GIF_MIME_TYPE: String
258
315
  JPEG_MIME_TYPE: String
@@ -269,9 +326,9 @@ module X
269
326
  def chunked_upload: (client: Client, file_path: String, media_category: String, ?media_type: String, ?boundary: String, ?chunk_size_mb: Integer) -> untyped
270
327
  def await_processing: (client: Client, media: untyped) -> untyped
271
328
  def await_processing!: (client: Client, media: untyped) -> untyped
329
+ def infer_media_type: (String file_path, String media_category) -> String
272
330
 
273
331
  private
274
- def infer_media_type: (String file_path, String media_category) -> String
275
332
  def split: (String file_path, Integer chunk_size) -> Array[String]
276
333
  def init: (client: Client, file_path: String, media_type: String, media_category: String) -> untyped
277
334
  def append: (client: Client, file_paths: Array[String], media: untyped, ?boundary: String) -> Array[String]
@@ -288,4 +345,23 @@ module X
288
345
  def validate_file_path!: (file_path: String) -> nil
289
346
  def validate_media_category!: (media_category: String) -> nil
290
347
  end
348
+
349
+ module AccountUploader
350
+ V1_BASE_URL: String
351
+ SUPPORTED_EXTENSIONS: Array[String]
352
+ MIME_TYPE_MAP: Hash[String, String]
353
+ extend AccountUploader
354
+
355
+ def update_profile_image: (client: Client, file_path: String, ?boundary: String) -> untyped
356
+ def upload_profile_image_binary: (client: Client, content: String, ?boundary: String) -> untyped
357
+ def update_profile_banner: (client: Client, file_path: String, ?width: Integer?, ?height: Integer?, ?offset_left: Integer?, ?offset_top: Integer?, ?boundary: String) -> untyped
358
+ def upload_profile_banner_binary: (client: Client, content: String, ?width: Integer?, ?height: Integer?, ?offset_left: Integer?, ?offset_top: Integer?, ?boundary: String) -> untyped
359
+
360
+ private
361
+ def v1_client: (Client client) -> Client
362
+ def validate_file!: (String file_path) -> nil
363
+ def construct_multipart_body: (field_name: String, content: String, boundary: String) -> String
364
+ def construct_banner_body: (content: String, width: Integer?, height: Integer?, offset_left: Integer?, offset_top: Integer?, boundary: String) -> String
365
+ def multipart_field: (String name, untyped value, String boundary) -> String
366
+ end
291
367
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: x
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Erik Berlin
@@ -35,9 +35,11 @@ files:
35
35
  - bin/console
36
36
  - bin/setup
37
37
  - lib/x.rb
38
+ - lib/x/account_uploader.rb
38
39
  - lib/x/authenticator.rb
39
40
  - lib/x/bearer_token_authenticator.rb
40
41
  - lib/x/client.rb
42
+ - lib/x/client_credentials.rb
41
43
  - lib/x/connection.rb
42
44
  - lib/x/errors/bad_gateway.rb
43
45
  - lib/x/errors/bad_request.rb
@@ -49,6 +51,7 @@ files:
49
51
  - lib/x/errors/gone.rb
50
52
  - lib/x/errors/http_error.rb
51
53
  - lib/x/errors/internal_server_error.rb
54
+ - lib/x/errors/invalid_media_type.rb
52
55
  - lib/x/errors/network_error.rb
53
56
  - lib/x/errors/not_acceptable.rb
54
57
  - lib/x/errors/not_found.rb
@@ -61,11 +64,13 @@ files:
61
64
  - lib/x/errors/unprocessable_entity.rb
62
65
  - lib/x/media_upload_validator.rb
63
66
  - lib/x/media_uploader.rb
67
+ - lib/x/oauth2_authenticator.rb
64
68
  - lib/x/oauth_authenticator.rb
65
69
  - lib/x/rate_limit.rb
66
70
  - lib/x/redirect_handler.rb
67
71
  - lib/x/request_builder.rb
68
72
  - lib/x/response_parser.rb
73
+ - lib/x/stream_parser.rb
69
74
  - lib/x/version.rb
70
75
  - sig/x.rbs
71
76
  homepage: https://sferik.github.io/x-ruby
@@ -94,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
99
  - !ruby/object:Gem::Version
95
100
  version: '0'
96
101
  requirements: []
97
- rubygems_version: 3.6.9
102
+ rubygems_version: 4.0.7
98
103
  specification_version: 4
99
104
  summary: A Ruby interface to the X API.
100
105
  test_files: []