x-twitter-scraper 0.10.4 → 0.10.6

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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/README.md +69 -29
  4. data/lib/x_twitter_scraper/client.rb +0 -13
  5. data/lib/x_twitter_scraper/file_part.rb +0 -3
  6. data/lib/x_twitter_scraper/internal/transport/base_client.rb +3 -211
  7. data/lib/x_twitter_scraper/internal/transport/pooled_net_requester.rb +2 -56
  8. data/lib/x_twitter_scraper/internal/type/array_of.rb +1 -77
  9. data/lib/x_twitter_scraper/internal/type/base_model.rb +3 -133
  10. data/lib/x_twitter_scraper/internal/type/base_page.rb +0 -13
  11. data/lib/x_twitter_scraper/internal/type/boolean.rb +0 -38
  12. data/lib/x_twitter_scraper/internal/type/converter.rb +0 -136
  13. data/lib/x_twitter_scraper/internal/type/enum.rb +1 -80
  14. data/lib/x_twitter_scraper/internal/type/file_input.rb +0 -39
  15. data/lib/x_twitter_scraper/internal/type/hash_of.rb +1 -77
  16. data/lib/x_twitter_scraper/internal/type/request_parameters.rb +0 -13
  17. data/lib/x_twitter_scraper/internal/type/union.rb +0 -101
  18. data/lib/x_twitter_scraper/internal/type/unknown.rb +0 -40
  19. data/lib/x_twitter_scraper/internal/util.rb +2 -307
  20. data/lib/x_twitter_scraper/models/account_retrieve_response.rb +0 -3
  21. data/lib/x_twitter_scraper/models/compose_create_params.rb +0 -4
  22. data/lib/x_twitter_scraper/models/compose_create_response.rb +0 -4
  23. data/lib/x_twitter_scraper/models/credit_retrieve_balance_response.rb +0 -3
  24. data/lib/x_twitter_scraper/models/credit_topup_balance_response.rb +0 -3
  25. data/lib/x_twitter_scraper/models/draft_list_params.rb +0 -3
  26. data/lib/x_twitter_scraper/models/draw_export_params.rb +0 -3
  27. data/lib/x_twitter_scraper/models/draw_list_params.rb +0 -3
  28. data/lib/x_twitter_scraper/models/draw_run_response.rb +0 -3
  29. data/lib/x_twitter_scraper/models/embedded_tweet.rb +0 -3
  30. data/lib/x_twitter_scraper/models/event.rb +0 -3
  31. data/lib/x_twitter_scraper/models/event_list_params.rb +0 -3
  32. data/lib/x_twitter_scraper/models/extraction_estimate_cost_params.rb +0 -3
  33. data/lib/x_twitter_scraper/models/extraction_list_params.rb +0 -3
  34. data/lib/x_twitter_scraper/models/extraction_run_params.rb +0 -3
  35. data/lib/x_twitter_scraper/models/guest_wallet_create_response.rb +0 -3
  36. data/lib/x_twitter_scraper/models/guest_wallet_retrieve_status_response.rb +0 -3
  37. data/lib/x_twitter_scraper/models/guest_wallet_topup_response.rb +0 -3
  38. data/lib/x_twitter_scraper/models/radar_item.rb +0 -3
  39. data/lib/x_twitter_scraper/models/radar_retrieve_trending_topics_params.rb +0 -3
  40. data/lib/x_twitter_scraper/models/search_tweet.rb +0 -3
  41. data/lib/x_twitter_scraper/models/trend_list_params.rb +0 -3
  42. data/lib/x_twitter_scraper/models/webhook.rb +0 -3
  43. data/lib/x_twitter_scraper/models/x/communities/join_create_response.rb +0 -3
  44. data/lib/x_twitter_scraper/models/x/communities/join_delete_all_response.rb +0 -4
  45. data/lib/x_twitter_scraper/models/x/communities/tweet_list_by_community_params.rb +0 -4
  46. data/lib/x_twitter_scraper/models/x/communities/tweet_list_params.rb +0 -3
  47. data/lib/x_twitter_scraper/models/x/community_create_response.rb +0 -3
  48. data/lib/x_twitter_scraper/models/x/community_delete_response.rb +0 -3
  49. data/lib/x_twitter_scraper/models/x/community_retrieve_members_params.rb +0 -3
  50. data/lib/x_twitter_scraper/models/x/community_retrieve_moderators_params.rb +0 -4
  51. data/lib/x_twitter_scraper/models/x/community_retrieve_search_params.rb +0 -3
  52. data/lib/x_twitter_scraper/models/x/dm_retrieve_history_params.rb +0 -3
  53. data/lib/x_twitter_scraper/models/x/dm_retrieve_history_response.rb +0 -4
  54. data/lib/x_twitter_scraper/models/x/dm_send_response.rb +0 -3
  55. data/lib/x_twitter_scraper/models/x/list_retrieve_followers_params.rb +0 -3
  56. data/lib/x_twitter_scraper/models/x/list_retrieve_members_params.rb +0 -3
  57. data/lib/x_twitter_scraper/models/x/list_retrieve_tweets_params.rb +0 -3
  58. data/lib/x_twitter_scraper/models/x/media_upload_response.rb +0 -3
  59. data/lib/x_twitter_scraper/models/x/profile_update_avatar_response.rb +0 -3
  60. data/lib/x_twitter_scraper/models/x/profile_update_banner_response.rb +0 -3
  61. data/lib/x_twitter_scraper/models/x/profile_update_response.rb +0 -3
  62. data/lib/x_twitter_scraper/models/x/tweet_create_params.rb +0 -3
  63. data/lib/x_twitter_scraper/models/x/tweet_create_response.rb +0 -3
  64. data/lib/x_twitter_scraper/models/x/tweet_delete_response.rb +0 -3
  65. data/lib/x_twitter_scraper/models/x/tweet_detail.rb +0 -3
  66. data/lib/x_twitter_scraper/models/x/tweet_get_favoriters_params.rb +0 -3
  67. data/lib/x_twitter_scraper/models/x/tweet_get_quotes_params.rb +0 -3
  68. data/lib/x_twitter_scraper/models/x/tweet_get_replies_params.rb +0 -3
  69. data/lib/x_twitter_scraper/models/x/tweet_get_retweeters_params.rb +0 -3
  70. data/lib/x_twitter_scraper/models/x/tweet_get_thread_params.rb +0 -3
  71. data/lib/x_twitter_scraper/models/x/tweet_retrieve_response.rb +0 -3
  72. data/lib/x_twitter_scraper/models/x/tweet_search_params.rb +0 -3
  73. data/lib/x_twitter_scraper/models/x/tweets/like_create_response.rb +0 -3
  74. data/lib/x_twitter_scraper/models/x/tweets/like_delete_response.rb +0 -3
  75. data/lib/x_twitter_scraper/models/x/tweets/retweet_create_response.rb +0 -3
  76. data/lib/x_twitter_scraper/models/x/tweets/retweet_delete_response.rb +0 -3
  77. data/lib/x_twitter_scraper/models/x/user_remove_follower_response.rb +0 -3
  78. data/lib/x_twitter_scraper/models/x/user_retrieve_batch_params.rb +0 -3
  79. data/lib/x_twitter_scraper/models/x/user_retrieve_batch_response.rb +0 -3
  80. data/lib/x_twitter_scraper/models/x/user_retrieve_followers_params.rb +0 -3
  81. data/lib/x_twitter_scraper/models/x/user_retrieve_followers_you_know_params.rb +0 -4
  82. data/lib/x_twitter_scraper/models/x/user_retrieve_following_params.rb +0 -3
  83. data/lib/x_twitter_scraper/models/x/user_retrieve_likes_params.rb +0 -3
  84. data/lib/x_twitter_scraper/models/x/user_retrieve_media_params.rb +0 -3
  85. data/lib/x_twitter_scraper/models/x/user_retrieve_mentions_params.rb +0 -3
  86. data/lib/x_twitter_scraper/models/x/user_retrieve_replies_params.rb +0 -3
  87. data/lib/x_twitter_scraper/models/x/user_retrieve_search_params.rb +0 -3
  88. data/lib/x_twitter_scraper/models/x/user_retrieve_tweets_params.rb +0 -3
  89. data/lib/x_twitter_scraper/models/x/user_retrieve_verified_followers_params.rb +0 -4
  90. data/lib/x_twitter_scraper/models/x/users/follow_create_response.rb +0 -3
  91. data/lib/x_twitter_scraper/models/x/users/follow_delete_all_response.rb +0 -3
  92. data/lib/x_twitter_scraper/models/x/write_action_retrieve_response.rb +0 -3
  93. data/lib/x_twitter_scraper/models/x/x_account.rb +0 -3
  94. data/lib/x_twitter_scraper/models/x_get_article_response.rb +0 -4
  95. data/lib/x_twitter_scraper/request_options.rb +0 -2
  96. data/lib/x_twitter_scraper/resources/drafts.rb +0 -3
  97. data/lib/x_twitter_scraper/resources/draws.rb +0 -6
  98. data/lib/x_twitter_scraper/resources/events.rb +0 -3
  99. data/lib/x_twitter_scraper/resources/extractions.rb +0 -9
  100. data/lib/x_twitter_scraper/resources/guest_wallets.rb +0 -6
  101. data/lib/x_twitter_scraper/resources/monitors/keywords.rb +1 -1
  102. data/lib/x_twitter_scraper/resources/monitors.rb +1 -1
  103. data/lib/x_twitter_scraper/resources/radar.rb +0 -3
  104. data/lib/x_twitter_scraper/resources/support/tickets.rb +0 -6
  105. data/lib/x_twitter_scraper/resources/trends.rb +0 -3
  106. data/lib/x_twitter_scraper/resources/x/communities/join.rb +0 -6
  107. data/lib/x_twitter_scraper/resources/x/communities/tweets.rb +0 -7
  108. data/lib/x_twitter_scraper/resources/x/communities.rb +0 -16
  109. data/lib/x_twitter_scraper/resources/x/dm.rb +0 -6
  110. data/lib/x_twitter_scraper/resources/x/lists.rb +0 -9
  111. data/lib/x_twitter_scraper/resources/x/media.rb +0 -3
  112. data/lib/x_twitter_scraper/resources/x/profile.rb +0 -9
  113. data/lib/x_twitter_scraper/resources/x/tweets/like.rb +0 -6
  114. data/lib/x_twitter_scraper/resources/x/tweets/retweet.rb +0 -6
  115. data/lib/x_twitter_scraper/resources/x/tweets.rb +0 -24
  116. data/lib/x_twitter_scraper/resources/x/users/follow.rb +0 -6
  117. data/lib/x_twitter_scraper/resources/x/users.rb +0 -38
  118. data/lib/x_twitter_scraper/resources/x.rb +0 -3
  119. data/lib/x_twitter_scraper/version.rb +1 -1
  120. data/lib/x_twitter_scraper.rb +0 -5
  121. data/rbi/x_twitter_scraper/client.rbi +0 -4
  122. data/rbi/x_twitter_scraper/file_part.rbi +0 -1
  123. data/rbi/x_twitter_scraper/internal/transport/base_client.rbi +0 -19
  124. data/rbi/x_twitter_scraper/internal/transport/pooled_net_requester.rbi +0 -9
  125. data/rbi/x_twitter_scraper/internal/type/array_of.rbi +0 -10
  126. data/rbi/x_twitter_scraper/internal/type/base_model.rbi +0 -47
  127. data/rbi/x_twitter_scraper/internal/type/base_page.rbi +0 -4
  128. data/rbi/x_twitter_scraper/internal/type/boolean.rbi +0 -8
  129. data/rbi/x_twitter_scraper/internal/type/converter.rbi +0 -36
  130. data/rbi/x_twitter_scraper/internal/type/enum.rbi +0 -20
  131. data/rbi/x_twitter_scraper/internal/type/file_input.rbi +0 -10
  132. data/rbi/x_twitter_scraper/internal/type/hash_of.rbi +0 -10
  133. data/rbi/x_twitter_scraper/internal/type/request_parameters.rbi +0 -4
  134. data/rbi/x_twitter_scraper/internal/type/union.rbi +0 -18
  135. data/rbi/x_twitter_scraper/internal/type/unknown.rbi +0 -8
  136. data/rbi/x_twitter_scraper/internal/util.rbi +0 -75
  137. data/rbi/x_twitter_scraper/internal.rbi +0 -2
  138. data/rbi/x_twitter_scraper/request_options.rbi +0 -1
  139. data/rbi/x_twitter_scraper/resources/monitors/keywords.rbi +1 -1
  140. data/rbi/x_twitter_scraper/resources/monitors.rbi +1 -1
  141. data/sig/x_twitter_scraper/internal/transport/base_client.rbs +0 -1
  142. metadata +13 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7f4f7490097e2a6d503e322f7cc58ad97ee1969eb5d63630b51cabba1e1475fa
4
- data.tar.gz: e4d5168613a265fda0cf590313d0f636dad69fdde68cf01a62b117bc74669830
3
+ metadata.gz: 46ffcafe78f6098cd45fa1a0f213515a2fb7d789f27ced4809ac735108a33084
4
+ data.tar.gz: a69999072784ab52f468234a7bfe343ad687c34dec12c78d19ecfb90b26ddccb
5
5
  SHA512:
6
- metadata.gz: 25f7299ef958d3305df6f392af953a70b87aa1ae639486a90416e49c84fe27faaddd6472f4ba42349c6daf71353143f5a54026904321be69c115abbf63e93fdd
7
- data.tar.gz: b34e28eba91790af3eb1e585156557ffd631fefd835cc9b1d84b5a8a35e7b81c7b78a8e1a0d7bcbc08e5db872ec2295b1866fede239f4a634d5005450fd09d43
6
+ metadata.gz: 41655fce506cc950e43ff05a0387836d0b6476ac218988637e99e4bd6069b5f9cd541a9819f6623e4e1b8f71c2ce91bb302aba829703a7a31f847b4a1a300315
7
+ data.tar.gz: 910c622be7636cf6fe992ac2851849a12cd6cdf191a8a57d27eadffe9829c63c80434189a7209c6745e15bf476c6cd6dc58705961c47d0848c3e5b9c314c3d25
data/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.10.6 (2026-10-14)
4
+
5
+ [Full changelog from v0.10.5 to v0.10.6](https://github.com/Xquik-dev/x-twitter-scraper-ruby/compare/v0.10.5...v0.10.6)
6
+
7
+ The API and its behavior are the same as in 0.10.5.
8
+
9
+ ### Documentation
10
+
11
+ * The README uses sentence case headings, active voice and whole sentences. Its facts, links and legal lines stay the same.
12
+
13
+ ### Chores
14
+
15
+ * 24 development and test gems move to their latest stable release. The 3 runtime dependencies stay the same.
16
+
17
+ ## 0.10.5 (2026-10-13)
18
+
19
+ [Full changelog from v0.10.4 to v0.10.5](https://github.com/Xquik-dev/x-twitter-scraper-ruby/compare/v0.10.4...v0.10.5)
20
+
21
+ ### Documentation
22
+
23
+ * The README title is now "X API & Twitter API Ruby SDK by Xquik".
24
+ * The README says near the top what Xquik is, how it bills and that it is not affiliated with X Corp.
25
+ * Doc comments use the current price. An active monitor costs 30 credits per hour.
26
+ * The gem page gains a description and links to the docs, the changelog and the issue tracker.
27
+
3
28
  ## 0.10.4 (2026-08-21)
4
29
 
5
30
  Full Changelog: [v0.10.3...v0.10.4](https://github.com/Xquik-dev/x-twitter-scraper-ruby/compare/v0.10.3...v0.10.4)
data/README.md CHANGED
@@ -1,16 +1,56 @@
1
- # Xquik Ruby SDK: Twitter search, followers & X automation
1
+ # X API & Twitter API Ruby SDK by Xquik
2
2
 
3
3
  [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/13739/badge)](https://www.bestpractices.dev/projects/13739)
4
4
 
5
- Use the Xquik Ruby SDK for Twitter search, timelines, profiles & followers.
6
- Manage media, webhooks & X automation with typed requests.
7
- Use documented Xquik REST routes as a Twitter API alternative.
5
+ Use this X API & Twitter API SDK to work with X from Ruby.
6
+ It works as a Twitter scraper & tweet scraper for search, profiles & followers.
7
+ Scrape Twitter timelines, lists, communities & trends into typed results.
8
+ Manage media, webhooks, monitors & X automation with typed requests.
9
+ It provides a Twitter API alternative through documented Xquik REST routes.
8
10
 
9
- [Ruby SDK Guide](https://docs.xquik.com/sdks/ruby) | [REST API](https://docs.xquik.com/api-reference/overview) | [RubyDoc](https://gemdocs.org/gems/x-twitter-scraper) | [Webhooks](https://docs.xquik.com/api-reference/webhooks/create)
11
+ Xquik is the world's fastest and cheapest X Twitter scraper service with the most complete X data.
12
+ Xquik charges only for delivered, unique, filter-matching results and never pads rows.
13
+
14
+ > Xquik is an independent third-party service. Not affiliated with X Corp.
15
+ > "Twitter" and "X" are trademarks of X Corp.
16
+
17
+ [Ruby SDK guide](https://docs.xquik.com/sdks/ruby) | [REST API](https://docs.xquik.com/api-reference/overview) | [RubyDoc](https://gemdocs.org/gems/x-twitter-scraper) | [Webhooks](https://docs.xquik.com/api-reference/webhooks/create)
18
+
19
+ <!-- trust:start -->
20
+
21
+ ## Trust & usage
22
+
23
+ [![Twitter API package downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fxquik.com%2Fbadges%2Fdownloads.json)](https://xquik.com/trust#downloads)
24
+ [![Twitter scraper users on Apify](https://img.shields.io/endpoint?url=https%3A%2F%2Fxquik.com%2Fbadges%2Fapify-users.json)](https://apify.com/xquik)
25
+ [![Twitter scraper runs on Apify](https://img.shields.io/endpoint?url=https%3A%2F%2Fxquik.com%2Fbadges%2Fapify-runs.json)](https://apify.com/xquik)
26
+ [![Tweet scraper rating on Apify](https://img.shields.io/endpoint?url=https%3A%2F%2Fxquik.com%2Fbadges%2Fapify-rating.json)](https://apify.com/xquik/x-tweet-scraper/reviews)
27
+ [![Xquik Twitter API accounts](https://img.shields.io/endpoint?url=https%3A%2F%2Fxquik.com%2Fbadges%2Faccounts.json)](https://xquik.com/trust#accounts)
28
+ [![Twitter Skill installs](https://img.shields.io/endpoint?url=https%3A%2F%2Fxquik.com%2Fbadges%2Fskill-installs.json)](https://xquik.com/trust#skill-installs)
29
+ [![Xquik verified revenue on TrustMRR](https://img.shields.io/endpoint?url=https%3A%2F%2Fxquik.com%2Fbadges%2Frevenue.json)](https://trustmrr.com/startup/xquik)
30
+ [![Twitter API median response time](https://img.shields.io/endpoint?url=https%3A%2F%2Fxquik.com%2Fbadges%2Frest-p50.json)](https://xquik.com/trust#speed)
31
+ [![Xquik GitHub stars](https://img.shields.io/endpoint?url=https%3A%2F%2Fxquik.com%2Fbadges%2Fgithub-stars.json)](https://github.com/Xquik-dev)
32
+ [![x-twitter-scraper downloads on RubyGems](https://img.shields.io/endpoint?url=https%3A%2F%2Fxquik.com%2Fbadges%2Frubygems-x-twitter-scraper.json)](https://rubygems.org/gems/x-twitter-scraper)
33
+ [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/13739/badge)](https://www.bestpractices.dev/projects/13739)
34
+
35
+ - 51,000+ downloads of Xquik's Twitter API packages on npm, PyPI, RubyGems, NuGet, Packagist & Terraform ([source](https://xquik.com/trust#downloads)) <!-- trust:downloads 51020 -->
36
+ - 7,800+ users of Xquik's Twitter scraper Actors on Apify ([source](https://apify.com/xquik)) <!-- trust:apify-users 7800 -->
37
+ - 5,700,000+ runs of Xquik's Twitter scraper Actors on Apify ([source](https://apify.com/xquik)) <!-- trust:apify-runs 5704701 -->
38
+ - 4.66 of 5 for the X Tweet Scraper from 16 Apify reviews ([source](https://apify.com/xquik/x-tweet-scraper/reviews)) <!-- trust:apify-rating 4.66 16 -->
39
+ - 3,900+ accounts on xquik.com ([source](https://xquik.com/trust#accounts)) <!-- trust:accounts 3924 -->
40
+ - 1,600+ installs of Xquik's Twitter Skills on skills.sh ([source](https://xquik.com/trust#skill-installs)) <!-- trust:skill-installs 1612 -->
41
+ - $38,000+ in revenue verified by TrustMRR ([source](https://trustmrr.com/startup/xquik)) <!-- trust:revenue 38115 -->
42
+ - 501 ms median REST API read time over the last 7 days ([source](https://xquik.com/trust#speed)) <!-- trust:rest-p50 501 -->
43
+ - 370+ GitHub stars across Xquik's repos ([source](https://github.com/Xquik-dev)) <!-- trust:github-stars 374 -->
44
+ - 9,900+ downloads of x-twitter-scraper on RubyGems ([source](https://rubygems.org/gems/x-twitter-scraper)) <!-- trust:rubygems-x-twitter-scraper 9982 -->
45
+ - This repo meets the OpenSSF Best Practices passing criteria ([source](https://www.bestpractices.dev/projects/13739)) <!-- trust:openssf-x-twitter-scraper-ruby 1 -->
46
+
47
+ Checked on 2026-10-15. See each number with its date & source on [xquik.com/trust](https://xquik.com/trust) or as [JSON](https://xquik.com/trust.json).
48
+
49
+ <!-- trust:end -->
10
50
 
11
51
  ## Common Twitter & X tasks
12
52
 
13
- | Task | REST Route | Usage |
53
+ | Task | REST route | Usage |
14
54
  | --- | --- | --- |
15
55
  | Search tweets without the X API | `GET /x/tweets/search` | Use keyword or advanced operator queries. |
16
56
  | Read an X profile timeline | `GET /x/users/{id}/tweets` | Paginate bounded results. |
@@ -24,18 +64,14 @@ Use documented Xquik REST routes as a Twitter API alternative.
24
64
 
25
65
  ## Installation
26
66
 
27
- Requires Ruby 3.2.0 or higher.
28
-
29
- Add the gem to your `Gemfile`:
67
+ The SDK requires Ruby 3.2.0 or later.
30
68
 
31
- <!-- x-release-please-start-version -->
69
+ Add the gem to your `Gemfile`.
32
70
 
33
71
  ```ruby
34
- gem "x-twitter-scraper", "~> 0.10.4"
72
+ gem "x-twitter-scraper", "~> 0.10.6"
35
73
  ```
36
74
 
37
- <!-- x-release-please-end -->
38
-
39
75
  ## Usage
40
76
 
41
77
  ```ruby
@@ -43,7 +79,7 @@ require "bundler/setup"
43
79
  require "x_twitter_scraper"
44
80
 
45
81
  x_twitter_scraper = XTwitterScraper::Client.new(
46
- api_key: ENV["X_TWITTER_SCRAPER_API_KEY"] # Optional; the client reads this variable.
82
+ api_key: ENV["X_TWITTER_SCRAPER_API_KEY"] # Optional. The client reads this variable.
47
83
  )
48
84
 
49
85
  response = x_twitter_scraper.x.tweets.search(q: "from:elonmusk", limit: 10)
@@ -53,7 +89,7 @@ puts(response)
53
89
 
54
90
  ### Handling errors
55
91
 
56
- The SDK raises an `APIError` subclass for connection failures and non-2xx responses:
92
+ The SDK raises an `APIError` subclass for connection failures and non-2xx responses.
57
93
 
58
94
  ```ruby
59
95
  begin
@@ -69,7 +105,7 @@ rescue XTwitterScraper::Errors::APIStatusError => e
69
105
  end
70
106
  ```
71
107
 
72
- | Cause | Error Type |
108
+ | Cause | Error type |
73
109
  | ---------------- | -------------------------- |
74
110
  | HTTP 400 | `BadRequestError` |
75
111
  | HTTP 401 | `AuthenticationError` |
@@ -87,7 +123,7 @@ end
87
123
 
88
124
  The SDK retries connection errors, timeouts & HTTP 408, 409, 429, and 5xx responses.
89
125
  It uses exponential backoff with 2 retries by default.
90
- Set `max_retries` to change or disable retries:
126
+ Set `max_retries` to change or disable retries.
91
127
 
92
128
  ```ruby
93
129
  # Change the client default.
@@ -101,7 +137,7 @@ x_twitter_scraper.account.retrieve(request_options: {max_retries: 5})
101
137
 
102
138
  ### Timeouts
103
139
 
104
- Requests time out after 60 seconds. Set `timeout` to change or disable this limit:
140
+ Requests time out after 60 seconds. Set `timeout` to change or disable this limit.
105
141
 
106
142
  ```ruby
107
143
  # Change the client default.
@@ -117,7 +153,7 @@ Timeouts raise `XTwitterScraper::Errors::APITimeoutError` and follow the retry p
117
153
 
118
154
  ## BaseModel
119
155
 
120
- All parameter and response objects inherit from `XTwitterScraper::Internal::Type::BaseModel` and support:
156
+ All parameter and response objects inherit from `XTwitterScraper::Internal::Type::BaseModel` and support these operations.
121
157
 
122
158
  1. Access known and unknown fields with `obj[:prop]`.
123
159
  2. Destructure fields with `obj => {prop: prop}` or pattern matching.
@@ -143,7 +179,7 @@ account =
143
179
  puts(account[:my_undocumented_property])
144
180
  ```
145
181
 
146
- Use `client.request` for undocumented endpoints while retaining authentication and retries:
182
+ Use `client.request` for undocumented endpoints. It keeps authentication and retries.
147
183
 
148
184
  ```ruby
149
185
  response = client.request(
@@ -159,7 +195,7 @@ response = client.request(
159
195
 
160
196
  Clients are thread-safe. Fork them only when no HTTP requests are in flight.
161
197
  Each client has an HTTP connection pool with a default size of 99.
162
- Reuse one client per application in most cases.
198
+ Reuse 1 client per application in most cases.
163
199
  Requests wait when every connection is busy. This wait counts toward the request timeout.
164
200
  Other SDK classes do not lock their data.
165
201
 
@@ -167,20 +203,18 @@ Other SDK classes do not lock their data.
167
203
 
168
204
  The gem ships [RBI](https://sorbet.org/docs/rbi) definitions without `sorbet-runtime`.
169
205
 
170
- Pass request hashes or typed parameter objects:
206
+ Pass request hashes or typed parameter objects.
171
207
 
172
208
  ```ruby
173
- # Hashes work without type safety:
174
209
  x_twitter_scraper.x.tweets.search(q: "from:elonmusk", limit: 10)
175
210
 
176
- # Splat a complete Params object:
177
211
  params = XTwitterScraper::X::TweetSearchParams.new(q: "from:elonmusk", limit: 10)
178
212
  x_twitter_scraper.x.tweets.search(**params)
179
213
  ```
180
214
 
181
215
  ### Enums
182
216
 
183
- Tagged symbols replace [`T::Enum`](https://sorbet.org/docs/tenum) and remain runtime primitives:
217
+ Tagged symbols replace [`T::Enum`](https://sorbet.org/docs/tenum) and remain runtime primitives.
184
218
 
185
219
  ```ruby
186
220
  # :en
@@ -190,16 +224,14 @@ puts(XTwitterScraper::AccountUpdateLocaleParams::Locale::EN)
190
224
  T.reveal_type(XTwitterScraper::AccountUpdateLocaleParams::Locale::EN)
191
225
  ```
192
226
 
193
- Enum parameters accept constants or literal values:
227
+ Enum parameters accept constants or literal values.
194
228
 
195
229
  ```ruby
196
- # Enum constants preserve tagged type information:
197
230
  x_twitter_scraper.account.update_locale(
198
231
  locale: XTwitterScraper::AccountUpdateLocaleParams::Locale::EN,
199
232
  # …
200
233
  )
201
234
 
202
- # Literal values also work:
203
235
  x_twitter_scraper.account.update_locale(
204
236
  locale: :en,
205
237
  # …
@@ -210,7 +242,15 @@ x_twitter_scraper.account.update_locale(
210
242
 
211
243
  This package follows [SemVer](https://semver.org/spec/v2.0.0.html). Version `0` releases may change APIs.
212
244
 
213
- Changes to non-runtime `*.rbi` and `*.rbs` definitions remain non-breaking.
245
+ Changes to non-runtime `*.rbi` and `*.rbs` definitions are non-breaking.
246
+
247
+ ## More Xquik tools
248
+
249
+ - [X (Twitter) scraper API & Twitter MCP server](https://github.com/Xquik-dev/x-twitter-scraper) with REST, MCP & Skill setup.
250
+ - Twitter API SDKs for [TypeScript](https://github.com/Xquik-dev/x-twitter-scraper-typescript), [Python](https://github.com/Xquik-dev/x-twitter-scraper-python), [Go](https://github.com/Xquik-dev/x-twitter-scraper-go), [Java](https://github.com/Xquik-dev/x-twitter-scraper-java), [Kotlin](https://github.com/Xquik-dev/x-twitter-scraper-kotlin), [C#](https://github.com/Xquik-dev/x-twitter-scraper-csharp) & [PHP](https://github.com/Xquik-dev/x-twitter-scraper-php).
251
+ - [Twitter CLI & X CLI](https://github.com/Xquik-dev/x-twitter-scraper-cli) for terminal workflows.
252
+ - [Twitter advanced search operators](https://github.com/Xquik-dev/x-twitter-advanced-search) with tested examples.
253
+ - [Xquik X API & Twitter scraper](https://xquik.com) and the [Twitter API documentation](https://docs.xquik.com/api-reference/overview).
214
254
 
215
255
  ## Help & contributing
216
256
 
@@ -88,33 +88,20 @@ module XTwitterScraper
88
88
  # @return [XTwitterScraper::Resources::GuestWallets]
89
89
  attr_reader :guest_wallets
90
90
 
91
- # @api private
92
- #
93
- # @param security [Hash{Symbol=>Boolean}]
94
- #
95
- # @return [Hash{String=>String}]
96
91
  private def auth_headers(security:)
97
92
  {auth_api_key:, oauth_bearer:}.slice(*security.keys).values.reduce({}, :merge)
98
93
  end
99
94
 
100
- # @api private
101
- #
102
- # @return [Hash{String=>String}]
103
95
  private def auth_api_key
104
96
  {"x-api-key" => @api_key}
105
97
  end
106
98
 
107
- # @api private
108
- #
109
- # @return [Hash{String=>String}]
110
99
  private def oauth_bearer
111
100
  return {} if @bearer_token.nil?
112
101
 
113
102
  {"authorization" => "Bearer #{@bearer_token}"}
114
103
  end
115
104
 
116
- # Creates and returns a new client for interacting with the API.
117
- #
118
105
  # @param api_key [String, nil] Defaults to `ENV["X_TWITTER_SCRAPER_API_KEY"]`
119
106
  #
120
107
  # @param bearer_token [String, nil] OAuth 2.1 access token Defaults to `ENV["X_TWITTER_SCRAPER_BEARER_TOKEN"]`
@@ -15,9 +15,6 @@ module XTwitterScraper
15
15
  # @return [String, nil]
16
16
  attr_reader :filename
17
17
 
18
- # @api private
19
- #
20
- # @return [String]
21
18
  private def read
22
19
  case content
23
20
  in Pathname
@@ -7,16 +7,12 @@
7
7
  module XTwitterScraper
8
8
  module Internal
9
9
  module Transport
10
- # @api private
11
- #
12
- # @abstract
13
10
  class BaseClient
14
11
  extend XTwitterScraper::Internal::Util::SorbetRuntimeSupport
15
12
 
16
- # from whatwg fetch spec
17
13
  MAX_REDIRECTS = 20
18
14
 
19
- # rubocop:disable Style/MutableConstant
15
+ # rubocop:disable-next Style/MutableConstant
20
16
  PLATFORM_HEADERS =
21
17
  {
22
18
  "x-stainless-arch" => XTwitterScraper::Internal::Util.arch,
@@ -26,14 +22,8 @@ module XTwitterScraper
26
22
  "x-stainless-runtime" => ::RUBY_ENGINE,
27
23
  "x-stainless-runtime-version" => ::RUBY_ENGINE_VERSION
28
24
  }
29
- # rubocop:enable Style/MutableConstant
30
25
 
31
26
  class << self
32
- # @api private
33
- #
34
- # @param req [Hash{Symbol=>Object}]
35
- #
36
- # @raise [ArgumentError]
37
27
  def validate!(req)
38
28
  keys = [
39
29
  :method,
@@ -60,50 +50,18 @@ module XTwitterScraper
60
50
  end
61
51
  end
62
52
 
63
- # @api private
64
- #
65
- # @param status [Integer]
66
- # @param headers [Hash{String=>String}]
67
- #
68
- # @return [Boolean]
69
53
  def should_retry?(status, headers:)
70
54
  coerced = XTwitterScraper::Internal::Util.coerce_boolean(headers["x-should-retry"])
71
55
  case [coerced, status]
72
56
  in [true | false, _]
73
57
  coerced
74
58
  in [_, 408 | 409 | 429 | (500..)]
75
- # retry on:
76
- # 408: timeouts
77
- # 409: locks
78
- # 429: rate limits
79
- # 500+: unknown errors
80
59
  true
81
60
  else
82
61
  false
83
62
  end
84
63
  end
85
64
 
86
- # @api private
87
- #
88
- # @param request [Hash{Symbol=>Object}] .
89
- #
90
- # @option request [Symbol] :method
91
- #
92
- # @option request [URI::Generic] :url
93
- #
94
- # @option request [Hash{String=>String}] :headers
95
- #
96
- # @option request [Object] :body
97
- #
98
- # @option request [Integer] :max_retries
99
- #
100
- # @option request [Float] :timeout
101
- #
102
- # @param status [Integer]
103
- #
104
- # @param response_headers [Hash{String=>String}]
105
- #
106
- # @return [Hash{Symbol=>Object}]
107
65
  def follow_redirect(request, status:, response_headers:)
108
66
  method, url, headers = request.fetch_values(:method, :url, :headers)
109
67
  location =
@@ -132,7 +90,6 @@ module XTwitterScraper
132
90
  nil
133
91
  end
134
92
 
135
- # from whatwg fetch spec
136
93
  case [status, method]
137
94
  in [301 | 302, :post] | [303, _]
138
95
  drop = %w[content-encoding content-language content-length content-location content-type]
@@ -145,7 +102,6 @@ module XTwitterScraper
145
102
  else
146
103
  end
147
104
 
148
- # from undici
149
105
  if XTwitterScraper::Internal::Util.uri_origin(url) != XTwitterScraper::Internal::Util.uri_origin(location)
150
106
  drop = %w[authorization cookie host proxy-authorization]
151
107
  request = {**request, headers: request.fetch(:headers).except(*drop)}
@@ -154,10 +110,6 @@ module XTwitterScraper
154
110
  request
155
111
  end
156
112
 
157
- # @api private
158
- #
159
- # @param status [Integer, XTwitterScraper::Errors::APIConnectionError]
160
- # @param stream [Enumerable<String>, nil]
161
113
  def reap_connection!(status, stream:)
162
114
  case status
163
115
  in (..199) | (300..499)
@@ -169,40 +121,8 @@ module XTwitterScraper
169
121
  end
170
122
  end
171
123
 
172
- # @return [URI::Generic]
173
- attr_reader :base_url
124
+ attr_reader :base_url, :timeout, :max_retries, :initial_retry_delay, :max_retry_delay, :headers, :idempotency_header, :requester
174
125
 
175
- # @return [Float]
176
- attr_reader :timeout
177
-
178
- # @return [Integer]
179
- attr_reader :max_retries
180
-
181
- # @return [Float]
182
- attr_reader :initial_retry_delay
183
-
184
- # @return [Float]
185
- attr_reader :max_retry_delay
186
-
187
- # @return [Hash{String=>String}]
188
- attr_reader :headers
189
-
190
- # @return [String, nil]
191
- attr_reader :idempotency_header
192
-
193
- # @api private
194
- # @return [XTwitterScraper::Internal::Transport::PooledNetRequester]
195
- attr_reader :requester
196
-
197
- # @api private
198
- #
199
- # @param base_url [String]
200
- # @param timeout [Float]
201
- # @param max_retries [Integer]
202
- # @param initial_retry_delay [Float]
203
- # @param max_retry_delay [Float]
204
- # @param headers [Hash{String=>String, Integer, Array<String, Integer, nil>, nil}]
205
- # @param idempotency_header [String, nil]
206
126
  def initialize(
207
127
  base_url:,
208
128
  timeout: 0.0,
@@ -231,60 +151,12 @@ module XTwitterScraper
231
151
  @max_retry_delay = max_retry_delay
232
152
  end
233
153
 
234
- # @api private
235
- #
236
- # @return [Hash{String=>String}]
237
154
  private def auth_headers = {}
238
155
 
239
- # @api private
240
- #
241
- # @return [String]
242
156
  private def user_agent = "#{self.class.name}/Ruby #{XTwitterScraper::VERSION}"
243
157
 
244
- # @api private
245
- #
246
- # @return [String]
247
158
  private def generate_idempotency_key = "stainless-ruby-retry-#{SecureRandom.uuid}"
248
159
 
249
- # @api private
250
- #
251
- # @param req [Hash{Symbol=>Object}] .
252
- #
253
- # @option req [Symbol] :method
254
- #
255
- # @option req [String, Array<String>] :path
256
- #
257
- # @option req [Hash{String=>Array<String>, String, nil}, nil] :query
258
- #
259
- # @option req [Hash{String=>String, Integer, Array<String, Integer, nil>, nil}, nil] :headers
260
- #
261
- # @option req [Object, nil] :body
262
- #
263
- # @option req [Symbol, Integer, Array<Symbol, Integer>, Proc, nil] :unwrap
264
- #
265
- # @option req [Class<XTwitterScraper::Internal::Type::BasePage>, nil] :page
266
- #
267
- # @option req [Class<XTwitterScraper::Internal::Type::BaseStream>, nil] :stream
268
- #
269
- # @option req [XTwitterScraper::Internal::Type::Converter, Class, nil] :model
270
- #
271
- # @option req [Hash{Symbol=>Boolean}, nil] :security
272
- #
273
- # @param opts [Hash{Symbol=>Object}] .
274
- #
275
- # @option opts [String, nil] :idempotency_key
276
- #
277
- # @option opts [Hash{String=>Array<String>, String, nil}, nil] :extra_query
278
- #
279
- # @option opts [Hash{String=>String, nil}, nil] :extra_headers
280
- #
281
- # @option opts [Object, nil] :extra_body
282
- #
283
- # @option opts [Integer, nil] :max_retries
284
- #
285
- # @option opts [Float, nil] :timeout
286
- #
287
- # @return [Hash{Symbol=>Object}]
288
160
  private def build_request(req, opts)
289
161
  method, uninterpolated_path = req.fetch_values(:method, :path)
290
162
 
@@ -328,9 +200,6 @@ module XTwitterScraper
328
200
  XTwitterScraper::Internal::Util.deep_merge(*[req[:body], opts[:extra_body]].compact)
329
201
  end
330
202
 
331
- # Generated methods always pass `req[:body]` for operations that define a
332
- # request body, so only elide the content-type header when the operation
333
- # has no body at all, not when an optional body param was omitted.
334
203
  headers.delete("content-type") if body.nil? && !req.key?(:body)
335
204
 
336
205
  url = XTwitterScraper::Internal::Util.join_parsed_uri(
@@ -348,14 +217,7 @@ module XTwitterScraper
348
217
  }
349
218
  end
350
219
 
351
- # @api private
352
- #
353
- # @param headers [Hash{String=>String}]
354
- # @param retry_count [Integer]
355
- #
356
- # @return [Float]
357
220
  private def retry_delay(headers, retry_count:)
358
- # Non-standard extension
359
221
  span = Float(headers["retry-after-ms"], exception: false)&.then { _1 / 1000 }
360
222
  return span if span
361
223
 
@@ -374,30 +236,6 @@ module XTwitterScraper
374
236
  (@initial_retry_delay * scale * jitter).clamp(0, @max_retry_delay)
375
237
  end
376
238
 
377
- # @api private
378
- #
379
- # @param request [Hash{Symbol=>Object}] .
380
- #
381
- # @option request [Symbol] :method
382
- #
383
- # @option request [URI::Generic] :url
384
- #
385
- # @option request [Hash{String=>String}] :headers
386
- #
387
- # @option request [Object] :body
388
- #
389
- # @option request [Integer] :max_retries
390
- #
391
- # @option request [Float] :timeout
392
- #
393
- # @param redirect_count [Integer]
394
- #
395
- # @param retry_count [Integer]
396
- #
397
- # @param send_retry_header [Boolean]
398
- #
399
- # @raise [XTwitterScraper::Errors::APIError]
400
- # @return [Array(Integer, Net::HTTPResponse, Enumerable<String>)]
401
239
  def send_request(request, redirect_count:, retry_count:, send_retry_header:)
402
240
  url, headers, max_retries, timeout = request.fetch_values(:url, :headers, :max_retries, :timeout)
403
241
  input = {**request.except(:timeout), deadline: XTwitterScraper::Internal::Util.monotonic_secs + timeout}
@@ -467,47 +305,6 @@ module XTwitterScraper
467
305
  end
468
306
  end
469
307
 
470
- # Execute the request specified by `req`. This is the method that all resource
471
- # methods call into.
472
- #
473
- # @overload request(method, path, query: {}, headers: {}, body: nil, unwrap: nil, page: nil, stream: nil, model: XTwitterScraper::Internal::Type::Unknown, security: {auth_api_key: true, oauth_bearer: true}, options: {})
474
- #
475
- # @param method [Symbol]
476
- #
477
- # @param path [String, Array<String>]
478
- #
479
- # @param query [Hash{String=>Array<String>, String, nil}, nil]
480
- #
481
- # @param headers [Hash{String=>String, Integer, Array<String, Integer, nil>, nil}, nil]
482
- #
483
- # @param body [Object, nil]
484
- #
485
- # @param unwrap [Symbol, Integer, Array<Symbol, Integer>, Proc, nil]
486
- #
487
- # @param page [Class<XTwitterScraper::Internal::Type::BasePage>, nil]
488
- #
489
- # @param stream [Class<XTwitterScraper::Internal::Type::BaseStream>, nil]
490
- #
491
- # @param model [XTwitterScraper::Internal::Type::Converter, Class, nil]
492
- #
493
- # @param security [Hash{Symbol=>Boolean}, nil]
494
- #
495
- # @param options [XTwitterScraper::RequestOptions, Hash{Symbol=>Object}, nil] .
496
- #
497
- # @option options [String, nil] :idempotency_key
498
- #
499
- # @option options [Hash{String=>Array<String>, String, nil}, nil] :extra_query
500
- #
501
- # @option options [Hash{String=>String, nil}, nil] :extra_headers
502
- #
503
- # @option options [Object, nil] :extra_body
504
- #
505
- # @option options [Integer, nil] :max_retries
506
- #
507
- # @option options [Float, nil] :timeout
508
- #
509
- # @raise [XTwitterScraper::Errors::APIError]
510
- # @return [Object]
511
308
  def request(req)
512
309
  self.class.validate!(req)
513
310
  model = req.fetch(:model) { XTwitterScraper::Internal::Type::Unknown }
@@ -517,7 +314,6 @@ module XTwitterScraper
517
314
  request = build_request(req.except(:options), opts)
518
315
  url = request.fetch(:url)
519
316
 
520
- # Don't send the current retry count in the headers if the caller modified the header defaults.
521
317
  send_retry_header = request.fetch(:headers)["x-stainless-retry-count"] == "0"
522
318
  status, response, stream = send_request(
523
319
  request,
@@ -547,13 +343,9 @@ module XTwitterScraper
547
343
  end
548
344
  end
549
345
 
550
- # @api private
551
- #
552
- # @return [String]
553
346
  def inspect
554
- # rubocop:disable Layout/LineLength
347
+ # rubocop:disable-next Layout/LineLength
555
348
  "#<#{self.class.name}:0x#{object_id.to_s(16)} base_url=#{@base_url} max_retries=#{@max_retries} timeout=#{@timeout}>"
556
- # rubocop:enable Layout/LineLength
557
349
  end
558
350
 
559
351
  define_sorbet_constant!(:RequestComponents) do