diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 361b05c..bcd0522 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.5.7" + ".": "0.6.0" } diff --git a/.stats.yml b/.stats.yml index 4477ceb..722a8b3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 122 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/xquik/x-twitter-scraper-26de9a1d18b92c9472fcc289877ba281ae305db846b7b14065142e26c7637d72.yml -openapi_spec_hash: f90f7016413291fdcbedb986385dc3ae -config_hash: 17c84052d27489691ee6dd861cc56e24 +configured_endpoints: 123 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/xquik/x-twitter-scraper-323137ebb1ee9824cd9cfb63a325c0839deb81f17244e42e8154d6567e7af954.yml +openapi_spec_hash: 48da9c2747c1e7c474dd514d39c28c49 +config_hash: dab26921eb273c16e5570c0485c9ac2c diff --git a/CHANGELOG.md b/CHANGELOG.md index a12f29d..1b7c5ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.6.0 (2026-07-29) + +Full Changelog: [v0.5.7...v0.6.0](https://github.com/Xquik-dev/x-twitter-scraper-ruby/compare/v0.5.7...v0.6.0) + +### Features + +* **api:** api update ([d172abc](https://github.com/Xquik-dev/x-twitter-scraper-ruby/commit/d172abc0808630d97fdf92e38903f60519a34ae1)) +* **api:** api update ([7696e0c](https://github.com/Xquik-dev/x-twitter-scraper-ruby/commit/7696e0cb8c594b5c71fe1813dc84012100afb3fc)) + ## 0.5.7 (2026-07-28) Full Changelog: [v0.5.6...v0.5.7](https://github.com/Xquik-dev/x-twitter-scraper-ruby/compare/v0.5.6...v0.5.7) diff --git a/Gemfile.lock b/Gemfile.lock index cd96faa..0e69c94 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -11,7 +11,7 @@ GIT PATH remote: . specs: - x-twitter-scraper (0.5.7) + x-twitter-scraper (0.6.0) base64 cgi connection_pool diff --git a/README.md b/README.md index 7c75b38..890ab87 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Add the gem to your `Gemfile`: ```ruby -gem "x-twitter-scraper", "~> 0.5.7" +gem "x-twitter-scraper", "~> 0.6.0" ``` diff --git a/lib/x_twitter_scraper.rb b/lib/x_twitter_scraper.rb index d28b0f7..7bad21b 100644 --- a/lib/x_twitter_scraper.rb +++ b/lib/x_twitter_scraper.rb @@ -184,6 +184,8 @@ require_relative "x_twitter_scraper/models/winner" require_relative "x_twitter_scraper/models/x/account_bulk_retry_params" require_relative "x_twitter_scraper/models/x/account_bulk_retry_response" +require_relative "x_twitter_scraper/models/x/account_connection_attempt_retrieve_params" +require_relative "x_twitter_scraper/models/x/account_connection_attempt_retrieve_response" require_relative "x_twitter_scraper/models/x/account_connection_challenge_submit_params" require_relative "x_twitter_scraper/models/x/account_connection_challenge_submit_response" require_relative "x_twitter_scraper/models/x/account_create_params" @@ -304,6 +306,7 @@ require_relative "x_twitter_scraper/resources/trends" require_relative "x_twitter_scraper/resources/webhooks" require_relative "x_twitter_scraper/resources/x" +require_relative "x_twitter_scraper/resources/x/account_connection_attempts" require_relative "x_twitter_scraper/resources/x/account_connection_challenges" require_relative "x_twitter_scraper/resources/x/accounts" require_relative "x_twitter_scraper/resources/x/bookmarks" diff --git a/lib/x_twitter_scraper/models/compose_create_response.rb b/lib/x_twitter_scraper/models/compose_create_response.rb index 7034dd2..88c7ab4 100644 --- a/lib/x_twitter_scraper/models/compose_create_response.rb +++ b/lib/x_twitter_scraper/models/compose_create_response.rb @@ -57,6 +57,14 @@ class ComposePrepareResult < XTwitterScraper::Internal::Type::BaseModel # @return [String] required :next_step, String, api_name: :nextStep + # @!attribute radar_recommendations + # Sources and guidance for researching a fresh post angle. + # + # @return [Array] + required :radar_recommendations, + -> { XTwitterScraper::Internal::Type::ArrayOf[XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation] }, + api_name: :radarRecommendations + # @!attribute scorer_weights # Published signal names with unpublished weights as null. # @@ -97,7 +105,7 @@ class ComposePrepareResult < XTwitterScraper::Internal::Type::BaseModel # @return [Array, nil] optional :style_tweets, XTwitterScraper::Internal::Type::ArrayOf[String], api_name: :styleTweets - # @!method initialize(content_rules:, engagement_multipliers:, engagement_velocity:, follow_up_questions:, intent_url:, next_step:, scorer_weights:, source:, top_penalties:, saved_styles: nil, style_note: nil, style_tweets: nil) + # @!method initialize(content_rules:, engagement_multipliers:, engagement_velocity:, follow_up_questions:, intent_url:, next_step:, radar_recommendations:, scorer_weights:, source:, top_penalties:, saved_styles: nil, style_note: nil, style_tweets: nil) # Some parameter documentations has been truncated, see # {XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult} for more # details. @@ -114,6 +122,8 @@ class ComposePrepareResult < XTwitterScraper::Internal::Type::BaseModel # # @param next_step [String] # + # @param radar_recommendations [Array] Sources and guidance for researching a fresh post angle. + # # @param scorer_weights [Array] Published signal names with unpublished weights as null. # # @param source [String] Signal source and evidence limits. @@ -154,6 +164,57 @@ class EngagementMultiplier < XTwitterScraper::Internal::Type::BaseModel # @param multiplier [Symbol, :"Production weight not published by X"] end + class RadarRecommendation < XTwitterScraper::Internal::Type::BaseModel + # @!attribute endpoint + # Radar endpoint for this source. + # + # @return [String] + required :endpoint, String + + # @!attribute guidance + # Source-specific drafting guidance. + # + # @return [String] + required :guidance, String + + # @!attribute source + # + # @return [Symbol, XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source] + required :source, + enum: -> { XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source } + + # @!attribute use_for + # Current-topic research this source supports. + # + # @return [String] + required :use_for, String, api_name: :useFor + + # @!method initialize(endpoint:, guidance:, source:, use_for:) + # @param endpoint [String] Radar endpoint for this source. + # + # @param guidance [String] Source-specific drafting guidance. + # + # @param source [Symbol, XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source] + # + # @param use_for [String] Current-topic research this source supports. + + # @see XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation#source + module Source + extend XTwitterScraper::Internal::Type::Enum + + REDDIT = :reddit + GITHUB = :github + TRUSTMRR = :trustmrr + HACKER_NEWS = :hacker_news + GOOGLE_TRENDS = :google_trends + WIKIPEDIA = :wikipedia + POLYMARKET = :polymarket + + # @!method self.values + # @return [Array] + end + end + class ScorerWeight < XTwitterScraper::Internal::Type::BaseModel # @!attribute context # Signal direction and publication limit. diff --git a/lib/x_twitter_scraper/models/radar_item.rb b/lib/x_twitter_scraper/models/radar_item.rb index eadf4d8..74722de 100644 --- a/lib/x_twitter_scraper/models/radar_item.rb +++ b/lib/x_twitter_scraper/models/radar_item.rb @@ -24,6 +24,7 @@ class RadarItem < XTwitterScraper::Internal::Type::BaseModel required :created_at, Time, api_name: :createdAt # @!attribute language + # BCP-47 language code. und means the source did not identify a language. # # @return [String] required :language, String @@ -31,7 +32,18 @@ class RadarItem < XTwitterScraper::Internal::Type::BaseModel # @!attribute metadata # Source-specific fields. Shape varies per source: # - # - reddit: { subreddit: string, author: string } + # - reddit: { author, authorId?, subreddit, subredditId?, subredditSubscribers?, + # sourceFormat, score?, upvoteRatio?, estimatedUpvotes?, estimatedDownvotes?, + # numberComments?, numberCrossposts?, selftext?, contentUrl?, domain?, + # postHint?, linkFlairText?, distinguished?, totalAwardsReceived?, viewCount?, + # editedAt?, galleryImageUrls?, redditVideo?, archived?, contestMode?, + # isCrosspostable?, isMeta?, isNsfw?, isOriginalContent?, isRobotIndexable?, + # isSelf?, isSpoiler?, isVideo?, locked?, stickied? }. `score` is Reddit's + # public net score. Exact public upvote and downvote counts are not available. + # Estimated counts derive from the public score and upvote ratio, which Reddit + # may fuzz. Comment bodies are not included. Current items combine public + # listing discovery with server-rendered post data and use `sourceFormat: html`; + # `json` and `rss` remain for legacy rows. # - github: { starsToday: number } # - hacker_news: { points: number, numberComments: number } # - google_trends: { approxTraffic: number } @@ -39,10 +51,15 @@ class RadarItem < XTwitterScraper::Internal::Type::BaseModel # - wikipedia: { views: number } # - trustmrr: { mrr, growthPercent, last30Days, total, customers, # activeSubscriptions, onSale, xHandle?, category?, askingPrice?, country?, - # growthMrrPercent?, multiple?, paymentProvider?, rank? } + # foundedDate?, googleSearchImpressionsLast30Days?, growthMrrPercent?, + # multiple?, paymentProvider?, profitMarginLast30Days?, rank?, + # revenuePerVisitor?, targetAudience?, visitorsLast30Days? } For the startup + # growth source, xHandle is the founder's X username without @. The rank field + # is the source's revenue rank. Result order represents reported 30-day + # revenue-growth rank. # - # @return [Hash{Symbol=>Object}] - required :metadata, XTwitterScraper::Internal::Type::HashOf[XTwitterScraper::Internal::Type::Unknown] + # @return [XTwitterScraper::Models::RadarItem::Metadata] + required :metadata, -> { XTwitterScraper::RadarItem::Metadata } # @!attribute published_at # @@ -81,6 +98,7 @@ class RadarItem < XTwitterScraper::Internal::Type::BaseModel optional :description, String # @!attribute image_url + # Source image. Startup growth items return the logo here. # # @return [String, nil] optional :image_url, String, api_name: :imageUrl @@ -103,9 +121,9 @@ class RadarItem < XTwitterScraper::Internal::Type::BaseModel # # @param created_at [Time] # - # @param language [String] + # @param language [String] BCP-47 language code. und means the source did not identify a language. # - # @param metadata [Hash{Symbol=>Object}] Source-specific fields. Shape varies per source: + # @param metadata [XTwitterScraper::Models::RadarItem::Metadata] Source-specific fields. Shape varies per source: # # @param published_at [Time] # @@ -121,7 +139,7 @@ class RadarItem < XTwitterScraper::Internal::Type::BaseModel # # @param description [String] # - # @param image_url [String] + # @param image_url [String] Source image. Startup growth items return the logo here. # # @param url [String] @@ -142,6 +160,125 @@ module Category # @return [Array] end + # @see XTwitterScraper::Models::RadarItem#metadata + class Metadata < XTwitterScraper::Internal::Type::BaseModel + # @!attribute author + # + # @return [String, nil] + optional :author, String + + # @!attribute content_url + # + # @return [String, nil] + optional :content_url, String, api_name: :contentUrl + + # @!attribute estimated_downvotes + # + # @return [Integer, nil] + optional :estimated_downvotes, Integer, api_name: :estimatedDownvotes + + # @!attribute estimated_upvotes + # + # @return [Integer, nil] + optional :estimated_upvotes, Integer, api_name: :estimatedUpvotes + + # @!attribute number_comments + # + # @return [Integer, nil] + optional :number_comments, Integer, api_name: :numberComments + + # @!attribute score + # + # @return [Integer, nil] + optional :score, Integer + + # @!attribute selftext + # + # @return [String, nil] + optional :selftext, String + + # @!attribute source_format + # Current items use html. json and rss are retained for legacy rows. + # + # @return [Symbol, XTwitterScraper::Models::RadarItem::Metadata::SourceFormat, nil] + optional :source_format, + enum: -> { XTwitterScraper::RadarItem::Metadata::SourceFormat }, + api_name: :sourceFormat + + # @!attribute subreddit + # + # @return [String, nil] + optional :subreddit, String + + # @!attribute upvote_ratio + # + # @return [Float, nil] + optional :upvote_ratio, Float, api_name: :upvoteRatio + + # @!method initialize(author: nil, content_url: nil, estimated_downvotes: nil, estimated_upvotes: nil, number_comments: nil, score: nil, selftext: nil, source_format: nil, subreddit: nil, upvote_ratio: nil) + # Source-specific fields. Shape varies per source: + # + # - reddit: { author, authorId?, subreddit, subredditId?, subredditSubscribers?, + # sourceFormat, score?, upvoteRatio?, estimatedUpvotes?, estimatedDownvotes?, + # numberComments?, numberCrossposts?, selftext?, contentUrl?, domain?, + # postHint?, linkFlairText?, distinguished?, totalAwardsReceived?, viewCount?, + # editedAt?, galleryImageUrls?, redditVideo?, archived?, contestMode?, + # isCrosspostable?, isMeta?, isNsfw?, isOriginalContent?, isRobotIndexable?, + # isSelf?, isSpoiler?, isVideo?, locked?, stickied? }. `score` is Reddit's + # public net score. Exact public upvote and downvote counts are not available. + # Estimated counts derive from the public score and upvote ratio, which Reddit + # may fuzz. Comment bodies are not included. Current items combine public + # listing discovery with server-rendered post data and use `sourceFormat: html`; + # `json` and `rss` remain for legacy rows. + # - github: { starsToday: number } + # - hacker_news: { points: number, numberComments: number } + # - google_trends: { approxTraffic: number } + # - polymarket: { volume24hr: number } + # - wikipedia: { views: number } + # - trustmrr: { mrr, growthPercent, last30Days, total, customers, + # activeSubscriptions, onSale, xHandle?, category?, askingPrice?, country?, + # foundedDate?, googleSearchImpressionsLast30Days?, growthMrrPercent?, + # multiple?, paymentProvider?, profitMarginLast30Days?, rank?, + # revenuePerVisitor?, targetAudience?, visitorsLast30Days? } For the startup + # growth source, xHandle is the founder's X username without @. The rank field + # is the source's revenue rank. Result order represents reported 30-day + # revenue-growth rank. + # + # @param author [String] + # + # @param content_url [String] + # + # @param estimated_downvotes [Integer] + # + # @param estimated_upvotes [Integer] + # + # @param number_comments [Integer] + # + # @param score [Integer] + # + # @param selftext [String] + # + # @param source_format [Symbol, XTwitterScraper::Models::RadarItem::Metadata::SourceFormat] Current items use html. json and rss are retained for legacy rows. + # + # @param subreddit [String] + # + # @param upvote_ratio [Float] + + # Current items use html. json and rss are retained for legacy rows. + # + # @see XTwitterScraper::Models::RadarItem::Metadata#source_format + module SourceFormat + extend XTwitterScraper::Internal::Type::Enum + + HTML = :html + JSON = :json + RSS = :rss + + # @!method self.values + # @return [Array] + end + end + # @see XTwitterScraper::Models::RadarItem#source module Source extend XTwitterScraper::Internal::Type::Enum diff --git a/lib/x_twitter_scraper/models/x/account_connection_attempt_retrieve_params.rb b/lib/x_twitter_scraper/models/x/account_connection_attempt_retrieve_params.rb new file mode 100644 index 0000000..c702161 --- /dev/null +++ b/lib/x_twitter_scraper/models/x/account_connection_attempt_retrieve_params.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module XTwitterScraper + module Models + module X + # @see XTwitterScraper::Resources::X::AccountConnectionAttempts#retrieve + class AccountConnectionAttemptRetrieveParams < XTwitterScraper::Internal::Type::BaseModel + extend XTwitterScraper::Internal::Type::RequestParameters::Converter + include XTwitterScraper::Internal::Type::RequestParameters + + # @!attribute id + # + # @return [String] + required :id, String + + # @!method initialize(id:, request_options: {}) + # @param id [String] + # @param request_options [XTwitterScraper::RequestOptions, Hash{Symbol=>Object}] + end + end + end +end diff --git a/lib/x_twitter_scraper/models/x/account_connection_attempt_retrieve_response.rb b/lib/x_twitter_scraper/models/x/account_connection_attempt_retrieve_response.rb new file mode 100644 index 0000000..41abdc1 --- /dev/null +++ b/lib/x_twitter_scraper/models/x/account_connection_attempt_retrieve_response.rb @@ -0,0 +1,190 @@ +# frozen_string_literal: true + +module XTwitterScraper + module Models + module X + # The connection is still in progress. + # + # @see XTwitterScraper::Resources::X::AccountConnectionAttempts#retrieve + module AccountConnectionAttemptRetrieveResponse + extend XTwitterScraper::Internal::Type::Union + + # The connection is still in progress. + variant -> { XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptPending } + + # The account connected successfully. + variant -> { XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptSuccess } + + # The connection reached a final failure. + variant -> { XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptFailed } + + # Resumable account connection challenge. Submit the email code to finish the same connection attempt. + variant -> { XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge } + + class XAccountConnectionAttemptPending < XTwitterScraper::Internal::Type::BaseModel + # @!attribute id + # + # @return [String] + required :id, String + + # @!attribute object + # + # @return [Symbol, :x_account_connection_attempt] + required :object, const: :x_account_connection_attempt + + # @!attribute poll_after_ms + # + # @return [Integer] + required :poll_after_ms, Integer, api_name: :pollAfterMs + + # @!attribute status + # + # @return [Symbol, :pending] + required :status, const: :pending + + # @!method initialize(id:, poll_after_ms:, object: :x_account_connection_attempt, status: :pending) + # The connection is still in progress. + # + # @param id [String] + # @param poll_after_ms [Integer] + # @param object [Symbol, :x_account_connection_attempt] + # @param status [Symbol, :pending] + end + + class XAccountConnectionAttemptSuccess < XTwitterScraper::Internal::Type::BaseModel + # @!attribute id + # + # @return [String] + required :id, String + + # @!attribute object + # + # @return [Symbol, :x_account_connection_attempt] + required :object, const: :x_account_connection_attempt + + # @!attribute status + # + # @return [Symbol, :success] + required :status, const: :success + + # @!method initialize(id:, object: :x_account_connection_attempt, status: :success) + # The account connected successfully. + # + # @param id [String] + # @param object [Symbol, :x_account_connection_attempt] + # @param status [Symbol, :success] + end + + class XAccountConnectionAttemptFailed < XTwitterScraper::Internal::Type::BaseModel + # @!attribute id + # + # @return [String] + required :id, String + + # @!attribute error + # + # @return [String] + required :error, String + + # @!attribute object + # + # @return [Symbol, :x_account_connection_attempt] + required :object, const: :x_account_connection_attempt + + # @!attribute retryable + # + # @return [Boolean] + required :retryable, XTwitterScraper::Internal::Type::Boolean + + # @!attribute status + # + # @return [Symbol, :failed] + required :status, const: :failed + + # @!attribute reason + # + # @return [String, nil] + optional :reason, String + + # @!method initialize(id:, error:, retryable:, reason: nil, object: :x_account_connection_attempt, status: :failed) + # The connection reached a final failure. + # + # @param id [String] + # @param error [String] + # @param retryable [Boolean] + # @param reason [String] + # @param object [Symbol, :x_account_connection_attempt] + # @param status [Symbol, :failed] + end + + class XAccountConnectionChallenge < XTwitterScraper::Internal::Type::BaseModel + # @!attribute id + # + # @return [String] + required :id, String + + # @!attribute expires_at + # + # @return [Time] + required :expires_at, Time, api_name: :expiresAt + + # @!attribute message + # + # @return [String] + required :message, String + + # @!attribute object + # + # @return [Symbol, XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Object] + required :object, + enum: -> { XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Object } + + # @!attribute status + # + # @return [Symbol, XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Status] + required :status, + enum: -> { XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Status } + + # @!attribute username + # + # @return [String] + required :username, String + + # @!method initialize(id:, expires_at:, message:, object:, status:, username:) + # Resumable account connection challenge. Submit the email code to finish the same + # connection attempt. + # + # @param id [String] + # @param expires_at [Time] + # @param message [String] + # @param object [Symbol, XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Object] + # @param status [Symbol, XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Status] + # @param username [String] + + # @see XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge#object + module Object + extend XTwitterScraper::Internal::Type::Enum + + X_ACCOUNT_CONNECTION_CHALLENGE = :x_account_connection_challenge + + # @!method self.values + # @return [Array] + end + + # @see XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge#status + module Status + extend XTwitterScraper::Internal::Type::Enum + + REQUIRES_EMAIL_CODE = :requires_email_code + + # @!method self.values + # @return [Array] + end + end + + # @!method self.variants + # @return [Array(XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptPending, XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptSuccess, XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptFailed, XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge)] + end + end + end +end diff --git a/lib/x_twitter_scraper/models/x/account_create_params.rb b/lib/x_twitter_scraper/models/x/account_create_params.rb index 3b4f7fb..021ab2d 100644 --- a/lib/x_twitter_scraper/models/x/account_create_params.rb +++ b/lib/x_twitter_scraper/models/x/account_create_params.rb @@ -24,26 +24,26 @@ class AccountCreateParams < XTwitterScraper::Internal::Type::BaseModel # @return [String] required :password, String + # @!attribute totp_secret + # Authenticator App TOTP secret required for durable login + # + # @return [String] + required :totp_secret, String + # @!attribute username # X username # # @return [String] required :username, String - # @!attribute totp_secret - # TOTP secret for 2FA - # - # @return [String, nil] - optional :totp_secret, String - - # @!method initialize(email:, password:, username:, totp_secret: nil, request_options: {}) + # @!method initialize(email:, password:, totp_secret:, username:, request_options: {}) # @param email [String] Account email # # @param password [String] Account password # - # @param username [String] X username + # @param totp_secret [String] Authenticator App TOTP secret required for durable login # - # @param totp_secret [String] TOTP secret for 2FA + # @param username [String] X username # # @param request_options [XTwitterScraper::RequestOptions, Hash{Symbol=>Object}] end diff --git a/lib/x_twitter_scraper/models/x/account_create_response.rb b/lib/x_twitter_scraper/models/x/account_create_response.rb index eb39b5e..59c0108 100644 --- a/lib/x_twitter_scraper/models/x/account_create_response.rb +++ b/lib/x_twitter_scraper/models/x/account_create_response.rb @@ -7,63 +7,8 @@ module XTwitterScraper module Models module X - # @see XTwitterScraper::Resources::X::Accounts#create - class AccountCreateResponse < XTwitterScraper::Internal::Type::BaseModel - # @!attribute id - # - # @return [String] - required :id, String - - # @!attribute created_at - # - # @return [Time] - required :created_at, Time, api_name: :createdAt - - # @!attribute health - # - # @return [Symbol, XTwitterScraper::Models::X::AccountCreateResponse::Health] - required :health, enum: -> { XTwitterScraper::Models::X::AccountCreateResponse::Health } - - # @!attribute status - # - # @return [String] - required :status, String - - # @!attribute x_user_id - # - # @return [String] - required :x_user_id, String, api_name: :xUserId - - # @!attribute x_username - # - # @return [String] - required :x_username, String, api_name: :xUsername - - # @!method initialize(id:, created_at:, health:, status:, x_user_id:, x_username:) - # Sanitized X account summary returned by connect and reauth. - # - # @param id [String] - # @param created_at [Time] - # @param health [Symbol, XTwitterScraper::Models::X::AccountCreateResponse::Health] - # @param status [String] - # @param x_user_id [String] - # @param x_username [String] - - # @see XTwitterScraper::Models::X::AccountCreateResponse#health - module Health - extend XTwitterScraper::Internal::Type::Enum - - HEALTHY = :healthy - LOCKED = :locked - NEEDS_REAUTH = :needsReauth - RECOVERING = :recovering - SUSPENDED = :suspended - TEMPORARY_ISSUE = :temporaryIssue - - # @!method self.values - # @return [Array] - end - end + # @type [XTwitterScraper::Internal::Type::Converter] + AccountCreateResponse = XTwitterScraper::Internal::Type::Unknown end end end diff --git a/lib/x_twitter_scraper/models/x/account_reauth_params.rb b/lib/x_twitter_scraper/models/x/account_reauth_params.rb index 565b412..40a9ced 100644 --- a/lib/x_twitter_scraper/models/x/account_reauth_params.rb +++ b/lib/x_twitter_scraper/models/x/account_reauth_params.rb @@ -30,7 +30,7 @@ class AccountReauthParams < XTwitterScraper::Internal::Type::BaseModel optional :email, String # @!attribute totp_secret - # TOTP secret for 2FA re-authentication + # Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret. # # @return [String, nil] optional :totp_secret, String @@ -42,7 +42,7 @@ class AccountReauthParams < XTwitterScraper::Internal::Type::BaseModel # # @param email [String] Email for the X account (updates stored email) # - # @param totp_secret [String] TOTP secret for 2FA re-authentication + # @param totp_secret [String] Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret. # # @param request_options [XTwitterScraper::RequestOptions, Hash{Symbol=>Object}] end diff --git a/lib/x_twitter_scraper/models/x/x_account.rb b/lib/x_twitter_scraper/models/x/x_account.rb index 8cc5d85..ea1e42e 100644 --- a/lib/x_twitter_scraper/models/x/x_account.rb +++ b/lib/x_twitter_scraper/models/x/x_account.rb @@ -19,11 +19,11 @@ class XAccount < XTwitterScraper::Internal::Type::BaseModel required :created_at, Time, api_name: :createdAt # @!attribute health - # Derived connection health. `healthy` = session active. `needsReauth` = user must + # Derived connection health. `healthy` = ready to use. `needsReauth` = user must # submit fresh credentials. `locked` = X locked the account; unlock on x.com - # first. `suspended` = X banned the account. `recovering` = past cooldown, will - # auto-retry on next use. `temporaryIssue` = temporary connection problem; retry - # shortly. + # first. `suspended` = X banned the account. `recovering` = cooldown ended; the + # account can reconnect on its next use. `temporaryIssue` = temporary connection + # problem; wait before the next use. # # @return [Symbol, XTwitterScraper::Models::X::XAccount::Health] required :health, enum: -> { XTwitterScraper::X::XAccount::Health } @@ -63,7 +63,7 @@ class XAccount < XTwitterScraper::Internal::Type::BaseModel # # @param created_at [Time] # - # @param health [Symbol, XTwitterScraper::Models::X::XAccount::Health] Derived connection health. `healthy` = session active. `needsReauth` = user must + # @param health [Symbol, XTwitterScraper::Models::X::XAccount::Health] Derived connection health. `healthy` = ready to use. `needsReauth` = user must s # # @param status [String] # @@ -75,11 +75,11 @@ class XAccount < XTwitterScraper::Internal::Type::BaseModel # # @param cookies_obtained_at [Time] - # Derived connection health. `healthy` = session active. `needsReauth` = user must + # Derived connection health. `healthy` = ready to use. `needsReauth` = user must # submit fresh credentials. `locked` = X locked the account; unlock on x.com - # first. `suspended` = X banned the account. `recovering` = past cooldown, will - # auto-retry on next use. `temporaryIssue` = temporary connection problem; retry - # shortly. + # first. `suspended` = X banned the account. `recovering` = cooldown ended; the + # account can reconnect on its next use. `temporaryIssue` = temporary connection + # problem; wait before the next use. # # @see XTwitterScraper::Models::X::XAccount#health module Health diff --git a/lib/x_twitter_scraper/resources/compose.rb b/lib/x_twitter_scraper/resources/compose.rb index 9043e8b..b23282e 100644 --- a/lib/x_twitter_scraper/resources/compose.rb +++ b/lib/x_twitter_scraper/resources/compose.rb @@ -8,10 +8,10 @@ module XTwitterScraper module Resources # AI tweet composition, drafts, writing styles, and radar class Compose - # Run one step of Xquik's three-step writing workflow. Compose returns questions - # and editorial rules. Refine returns goal-specific guidance. Score applies - # deterministic text checks. It does not predict reach or expose X ranking - # weights. + # Run one step of Xquik's three-step writing workflow. Compose returns questions, + # editorial rules, and source-specific Radar recommendations. Refine returns + # goal-specific guidance. Score applies deterministic text checks. It does not + # predict reach or expose X ranking weights. # # @overload create(body:, request_options: {}) # diff --git a/lib/x_twitter_scraper/resources/x.rb b/lib/x_twitter_scraper/resources/x.rb index bda3b26..8dc776c 100644 --- a/lib/x_twitter_scraper/resources/x.rb +++ b/lib/x_twitter_scraper/resources/x.rb @@ -42,6 +42,10 @@ class X # @return [XTwitterScraper::Resources::X::AccountConnectionChallenges] attr_reader :account_connection_challenges + # Connected X account management + # @return [XTwitterScraper::Resources::X::AccountConnectionAttempts] + attr_reader :account_connection_attempts + # Look up, search, and analyze individual tweets # @return [XTwitterScraper::Resources::X::Bookmarks] attr_reader :bookmarks @@ -165,6 +169,8 @@ def initialize(client:) @accounts = XTwitterScraper::Resources::X::Accounts.new(client: client) @account_connection_challenges = XTwitterScraper::Resources::X::AccountConnectionChallenges.new(client: client) + @account_connection_attempts = + XTwitterScraper::Resources::X::AccountConnectionAttempts.new(client: client) @bookmarks = XTwitterScraper::Resources::X::Bookmarks.new(client: client) @lists = XTwitterScraper::Resources::X::Lists.new(client: client) end diff --git a/lib/x_twitter_scraper/resources/x/account_connection_attempts.rb b/lib/x_twitter_scraper/resources/x/account_connection_attempts.rb new file mode 100644 index 0000000..b1b9aee --- /dev/null +++ b/lib/x_twitter_scraper/resources/x/account_connection_attempts.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module XTwitterScraper + module Resources + class X + # Connected X account management + class AccountConnectionAttempts + # Get X account connection status + # + # @overload retrieve(id, request_options: {}) + # + # @param id [String] Connection attempt ID returned by `POST /x/accounts`. + # + # @param request_options [XTwitterScraper::RequestOptions, Hash{Symbol=>Object}, nil] + # + # @return [XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptPending, XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptSuccess, XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptFailed, XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge] + # + # @see XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveParams + def retrieve(id, params = {}) + @client.request( + method: :get, + path: ["x/account-connection-attempts/%1$s", id], + model: XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse, + options: params[:request_options] + ) + end + + # @api private + # + # @param client [XTwitterScraper::Client] + def initialize(client:) + @client = client + end + end + end + end +end diff --git a/lib/x_twitter_scraper/resources/x/accounts.rb b/lib/x_twitter_scraper/resources/x/accounts.rb index 1b7f5e9..7173624 100644 --- a/lib/x_twitter_scraper/resources/x/accounts.rb +++ b/lib/x_twitter_scraper/resources/x/accounts.rb @@ -11,19 +11,19 @@ class X class Accounts # Connect X account # - # @overload create(email:, password:, username:, totp_secret: nil, request_options: {}) + # @overload create(email:, password:, totp_secret:, username:, request_options: {}) # # @param email [String] Account email # # @param password [String] Account password # - # @param username [String] X username + # @param totp_secret [String] Authenticator App TOTP secret required for durable login # - # @param totp_secret [String] TOTP secret for 2FA + # @param username [String] X username # # @param request_options [XTwitterScraper::RequestOptions, Hash{Symbol=>Object}, nil] # - # @return [XTwitterScraper::Models::X::AccountCreateResponse] + # @return [Object] # # @see XTwitterScraper::Models::X::AccountCreateParams def create(params) @@ -32,7 +32,7 @@ def create(params) method: :post, path: "x/accounts", body: parsed, - model: XTwitterScraper::Models::X::AccountCreateResponse, + model: XTwitterScraper::Internal::Type::Unknown, options: options ) end @@ -124,7 +124,7 @@ def bulk_retry(params = {}) # # @param email [String] Email for the X account (updates stored email) # - # @param totp_secret [String] TOTP secret for 2FA re-authentication + # @param totp_secret [String] Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret. # # @param request_options [XTwitterScraper::RequestOptions, Hash{Symbol=>Object}, nil] # diff --git a/lib/x_twitter_scraper/version.rb b/lib/x_twitter_scraper/version.rb index 0847c91..ff0f83f 100644 --- a/lib/x_twitter_scraper/version.rb +++ b/lib/x_twitter_scraper/version.rb @@ -5,5 +5,5 @@ # frozen_string_literal: true module XTwitterScraper - VERSION = "0.5.7" + VERSION = "0.6.0" end diff --git a/rbi/x_twitter_scraper/models/compose_create_response.rbi b/rbi/x_twitter_scraper/models/compose_create_response.rbi index 68ee0c3..c1510f3 100644 --- a/rbi/x_twitter_scraper/models/compose_create_response.rbi +++ b/rbi/x_twitter_scraper/models/compose_create_response.rbi @@ -61,6 +61,16 @@ module XTwitterScraper sig { returns(String) } attr_accessor :next_step + # Sources and guidance for researching a fresh post angle. + sig do + returns( + T::Array[ + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation + ] + ) + end + attr_accessor :radar_recommendations + # Published signal names with unpublished weights as null. sig do returns( @@ -129,6 +139,10 @@ module XTwitterScraper follow_up_questions: T::Array[String], intent_url: String, next_step: String, + radar_recommendations: + T::Array[ + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::OrHash + ], scorer_weights: T::Array[ XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::ScorerWeight::OrHash @@ -154,6 +168,8 @@ module XTwitterScraper # X post intent seeded with the topic. intent_url:, next_step:, + # Sources and guidance for researching a fresh post angle. + radar_recommendations:, # Published signal names with unpublished weights as null. scorer_weights:, # Signal source and evidence limits. @@ -184,6 +200,10 @@ module XTwitterScraper follow_up_questions: T::Array[String], intent_url: String, next_step: String, + radar_recommendations: + T::Array[ + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation + ], scorer_weights: T::Array[ XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::ScorerWeight @@ -254,6 +274,128 @@ module XTwitterScraper end end + class RadarRecommendation < XTwitterScraper::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation, + XTwitterScraper::Internal::AnyHash + ) + end + + # Radar endpoint for this source. + sig { returns(String) } + attr_accessor :endpoint + + # Source-specific drafting guidance. + sig { returns(String) } + attr_accessor :guidance + + sig do + returns( + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source::TaggedSymbol + ) + end + attr_accessor :source + + # Current-topic research this source supports. + sig { returns(String) } + attr_accessor :use_for + + sig do + params( + endpoint: String, + guidance: String, + source: + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source::OrSymbol, + use_for: String + ).returns(T.attached_class) + end + def self.new( + # Radar endpoint for this source. + endpoint:, + # Source-specific drafting guidance. + guidance:, + source:, + # Current-topic research this source supports. + use_for: + ) + end + + sig do + override.returns( + { + endpoint: String, + guidance: String, + source: + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source::TaggedSymbol, + use_for: String + } + ) + end + def to_hash + end + + module Source + extend XTwitterScraper::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + REDDIT = + T.let( + :reddit, + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source::TaggedSymbol + ) + GITHUB = + T.let( + :github, + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source::TaggedSymbol + ) + TRUSTMRR = + T.let( + :trustmrr, + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source::TaggedSymbol + ) + HACKER_NEWS = + T.let( + :hacker_news, + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source::TaggedSymbol + ) + GOOGLE_TRENDS = + T.let( + :google_trends, + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source::TaggedSymbol + ) + WIKIPEDIA = + T.let( + :wikipedia, + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source::TaggedSymbol + ) + POLYMARKET = + T.let( + :polymarket, + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::Source::TaggedSymbol + ] + ) + end + def self.values + end + end + end + class ScorerWeight < XTwitterScraper::Internal::Type::BaseModel OrHash = T.type_alias do diff --git a/rbi/x_twitter_scraper/models/radar_item.rbi b/rbi/x_twitter_scraper/models/radar_item.rbi index e58c35e..bdb29d6 100644 --- a/rbi/x_twitter_scraper/models/radar_item.rbi +++ b/rbi/x_twitter_scraper/models/radar_item.rbi @@ -22,12 +22,24 @@ module XTwitterScraper sig { returns(Time) } attr_accessor :created_at + # BCP-47 language code. und means the source did not identify a language. sig { returns(String) } attr_accessor :language # Source-specific fields. Shape varies per source: # - # - reddit: { subreddit: string, author: string } + # - reddit: { author, authorId?, subreddit, subredditId?, subredditSubscribers?, + # sourceFormat, score?, upvoteRatio?, estimatedUpvotes?, estimatedDownvotes?, + # numberComments?, numberCrossposts?, selftext?, contentUrl?, domain?, + # postHint?, linkFlairText?, distinguished?, totalAwardsReceived?, viewCount?, + # editedAt?, galleryImageUrls?, redditVideo?, archived?, contestMode?, + # isCrosspostable?, isMeta?, isNsfw?, isOriginalContent?, isRobotIndexable?, + # isSelf?, isSpoiler?, isVideo?, locked?, stickied? }. `score` is Reddit's + # public net score. Exact public upvote and downvote counts are not available. + # Estimated counts derive from the public score and upvote ratio, which Reddit + # may fuzz. Comment bodies are not included. Current items combine public + # listing discovery with server-rendered post data and use `sourceFormat: html`; + # `json` and `rss` remain for legacy rows. # - github: { starsToday: number } # - hacker_news: { points: number, numberComments: number } # - google_trends: { approxTraffic: number } @@ -35,9 +47,19 @@ module XTwitterScraper # - wikipedia: { views: number } # - trustmrr: { mrr, growthPercent, last30Days, total, customers, # activeSubscriptions, onSale, xHandle?, category?, askingPrice?, country?, - # growthMrrPercent?, multiple?, paymentProvider?, rank? } - sig { returns(T::Hash[Symbol, T.anything]) } - attr_accessor :metadata + # foundedDate?, googleSearchImpressionsLast30Days?, growthMrrPercent?, + # multiple?, paymentProvider?, profitMarginLast30Days?, rank?, + # revenuePerVisitor?, targetAudience?, visitorsLast30Days? } For the startup + # growth source, xHandle is the founder's X username without @. The rank field + # is the source's revenue rank. Result order represents reported 30-day + # revenue-growth rank. + sig { returns(XTwitterScraper::RadarItem::Metadata) } + attr_reader :metadata + + sig do + params(metadata: XTwitterScraper::RadarItem::Metadata::OrHash).void + end + attr_writer :metadata sig { returns(Time) } attr_accessor :published_at @@ -64,6 +86,7 @@ module XTwitterScraper sig { params(description: String).void } attr_writer :description + # Source image. Startup growth items return the logo here. sig { returns(T.nilable(String)) } attr_reader :image_url @@ -84,7 +107,7 @@ module XTwitterScraper category: XTwitterScraper::RadarItem::Category::OrSymbol, created_at: Time, language: String, - metadata: T::Hash[Symbol, T.anything], + metadata: XTwitterScraper::RadarItem::Metadata::OrHash, published_at: Time, region: String, score: Float, @@ -101,10 +124,22 @@ module XTwitterScraper id:, category:, created_at:, + # BCP-47 language code. und means the source did not identify a language. language:, # Source-specific fields. Shape varies per source: # - # - reddit: { subreddit: string, author: string } + # - reddit: { author, authorId?, subreddit, subredditId?, subredditSubscribers?, + # sourceFormat, score?, upvoteRatio?, estimatedUpvotes?, estimatedDownvotes?, + # numberComments?, numberCrossposts?, selftext?, contentUrl?, domain?, + # postHint?, linkFlairText?, distinguished?, totalAwardsReceived?, viewCount?, + # editedAt?, galleryImageUrls?, redditVideo?, archived?, contestMode?, + # isCrosspostable?, isMeta?, isNsfw?, isOriginalContent?, isRobotIndexable?, + # isSelf?, isSpoiler?, isVideo?, locked?, stickied? }. `score` is Reddit's + # public net score. Exact public upvote and downvote counts are not available. + # Estimated counts derive from the public score and upvote ratio, which Reddit + # may fuzz. Comment bodies are not included. Current items combine public + # listing discovery with server-rendered post data and use `sourceFormat: html`; + # `json` and `rss` remain for legacy rows. # - github: { starsToday: number } # - hacker_news: { points: number, numberComments: number } # - google_trends: { approxTraffic: number } @@ -112,7 +147,12 @@ module XTwitterScraper # - wikipedia: { views: number } # - trustmrr: { mrr, growthPercent, last30Days, total, customers, # activeSubscriptions, onSale, xHandle?, category?, askingPrice?, country?, - # growthMrrPercent?, multiple?, paymentProvider?, rank? } + # foundedDate?, googleSearchImpressionsLast30Days?, growthMrrPercent?, + # multiple?, paymentProvider?, profitMarginLast30Days?, rank?, + # revenuePerVisitor?, targetAudience?, visitorsLast30Days? } For the startup + # growth source, xHandle is the founder's X username without @. The rank field + # is the source's revenue rank. Result order represents reported 30-day + # revenue-growth rank. metadata:, published_at:, region:, @@ -122,6 +162,7 @@ module XTwitterScraper source_id:, title:, description: nil, + # Source image. Startup growth items return the logo here. image_url: nil, url: nil ) @@ -134,7 +175,7 @@ module XTwitterScraper category: XTwitterScraper::RadarItem::Category::TaggedSymbol, created_at: Time, language: String, - metadata: T::Hash[Symbol, T.anything], + metadata: XTwitterScraper::RadarItem::Metadata, published_at: Time, region: String, score: Float, @@ -184,6 +225,202 @@ module XTwitterScraper end end + class Metadata < XTwitterScraper::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + XTwitterScraper::RadarItem::Metadata, + XTwitterScraper::Internal::AnyHash + ) + end + + sig { returns(T.nilable(String)) } + attr_reader :author + + sig { params(author: String).void } + attr_writer :author + + sig { returns(T.nilable(String)) } + attr_reader :content_url + + sig { params(content_url: String).void } + attr_writer :content_url + + sig { returns(T.nilable(Integer)) } + attr_reader :estimated_downvotes + + sig { params(estimated_downvotes: Integer).void } + attr_writer :estimated_downvotes + + sig { returns(T.nilable(Integer)) } + attr_reader :estimated_upvotes + + sig { params(estimated_upvotes: Integer).void } + attr_writer :estimated_upvotes + + sig { returns(T.nilable(Integer)) } + attr_reader :number_comments + + sig { params(number_comments: Integer).void } + attr_writer :number_comments + + sig { returns(T.nilable(Integer)) } + attr_reader :score + + sig { params(score: Integer).void } + attr_writer :score + + sig { returns(T.nilable(String)) } + attr_reader :selftext + + sig { params(selftext: String).void } + attr_writer :selftext + + # Current items use html. json and rss are retained for legacy rows. + sig do + returns( + T.nilable( + XTwitterScraper::RadarItem::Metadata::SourceFormat::TaggedSymbol + ) + ) + end + attr_reader :source_format + + sig do + params( + source_format: + XTwitterScraper::RadarItem::Metadata::SourceFormat::OrSymbol + ).void + end + attr_writer :source_format + + sig { returns(T.nilable(String)) } + attr_reader :subreddit + + sig { params(subreddit: String).void } + attr_writer :subreddit + + sig { returns(T.nilable(Float)) } + attr_reader :upvote_ratio + + sig { params(upvote_ratio: Float).void } + attr_writer :upvote_ratio + + # Source-specific fields. Shape varies per source: + # + # - reddit: { author, authorId?, subreddit, subredditId?, subredditSubscribers?, + # sourceFormat, score?, upvoteRatio?, estimatedUpvotes?, estimatedDownvotes?, + # numberComments?, numberCrossposts?, selftext?, contentUrl?, domain?, + # postHint?, linkFlairText?, distinguished?, totalAwardsReceived?, viewCount?, + # editedAt?, galleryImageUrls?, redditVideo?, archived?, contestMode?, + # isCrosspostable?, isMeta?, isNsfw?, isOriginalContent?, isRobotIndexable?, + # isSelf?, isSpoiler?, isVideo?, locked?, stickied? }. `score` is Reddit's + # public net score. Exact public upvote and downvote counts are not available. + # Estimated counts derive from the public score and upvote ratio, which Reddit + # may fuzz. Comment bodies are not included. Current items combine public + # listing discovery with server-rendered post data and use `sourceFormat: html`; + # `json` and `rss` remain for legacy rows. + # - github: { starsToday: number } + # - hacker_news: { points: number, numberComments: number } + # - google_trends: { approxTraffic: number } + # - polymarket: { volume24hr: number } + # - wikipedia: { views: number } + # - trustmrr: { mrr, growthPercent, last30Days, total, customers, + # activeSubscriptions, onSale, xHandle?, category?, askingPrice?, country?, + # foundedDate?, googleSearchImpressionsLast30Days?, growthMrrPercent?, + # multiple?, paymentProvider?, profitMarginLast30Days?, rank?, + # revenuePerVisitor?, targetAudience?, visitorsLast30Days? } For the startup + # growth source, xHandle is the founder's X username without @. The rank field + # is the source's revenue rank. Result order represents reported 30-day + # revenue-growth rank. + sig do + params( + author: String, + content_url: String, + estimated_downvotes: Integer, + estimated_upvotes: Integer, + number_comments: Integer, + score: Integer, + selftext: String, + source_format: + XTwitterScraper::RadarItem::Metadata::SourceFormat::OrSymbol, + subreddit: String, + upvote_ratio: Float + ).returns(T.attached_class) + end + def self.new( + author: nil, + content_url: nil, + estimated_downvotes: nil, + estimated_upvotes: nil, + number_comments: nil, + score: nil, + selftext: nil, + # Current items use html. json and rss are retained for legacy rows. + source_format: nil, + subreddit: nil, + upvote_ratio: nil + ) + end + + sig do + override.returns( + { + author: String, + content_url: String, + estimated_downvotes: Integer, + estimated_upvotes: Integer, + number_comments: Integer, + score: Integer, + selftext: String, + source_format: + XTwitterScraper::RadarItem::Metadata::SourceFormat::TaggedSymbol, + subreddit: String, + upvote_ratio: Float + } + ) + end + def to_hash + end + + # Current items use html. json and rss are retained for legacy rows. + module SourceFormat + extend XTwitterScraper::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all(Symbol, XTwitterScraper::RadarItem::Metadata::SourceFormat) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + HTML = + T.let( + :html, + XTwitterScraper::RadarItem::Metadata::SourceFormat::TaggedSymbol + ) + JSON = + T.let( + :json, + XTwitterScraper::RadarItem::Metadata::SourceFormat::TaggedSymbol + ) + RSS = + T.let( + :rss, + XTwitterScraper::RadarItem::Metadata::SourceFormat::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + XTwitterScraper::RadarItem::Metadata::SourceFormat::TaggedSymbol + ] + ) + end + def self.values + end + end + end + module Source extend XTwitterScraper::Internal::Type::Enum diff --git a/rbi/x_twitter_scraper/models/x/account_connection_attempt_retrieve_params.rbi b/rbi/x_twitter_scraper/models/x/account_connection_attempt_retrieve_params.rbi new file mode 100644 index 0000000..1909b18 --- /dev/null +++ b/rbi/x_twitter_scraper/models/x/account_connection_attempt_retrieve_params.rbi @@ -0,0 +1,40 @@ +# typed: strong + +module XTwitterScraper + module Models + module X + class AccountConnectionAttemptRetrieveParams < XTwitterScraper::Internal::Type::BaseModel + extend XTwitterScraper::Internal::Type::RequestParameters::Converter + include XTwitterScraper::Internal::Type::RequestParameters + + OrHash = + T.type_alias do + T.any( + XTwitterScraper::X::AccountConnectionAttemptRetrieveParams, + XTwitterScraper::Internal::AnyHash + ) + end + + sig { returns(String) } + attr_accessor :id + + sig do + params( + id: String, + request_options: XTwitterScraper::RequestOptions::OrHash + ).returns(T.attached_class) + end + def self.new(id:, request_options: {}) + end + + sig do + override.returns( + { id: String, request_options: XTwitterScraper::RequestOptions } + ) + end + def to_hash + end + end + end + end +end diff --git a/rbi/x_twitter_scraper/models/x/account_connection_attempt_retrieve_response.rbi b/rbi/x_twitter_scraper/models/x/account_connection_attempt_retrieve_response.rbi new file mode 100644 index 0000000..d0c2e17 --- /dev/null +++ b/rbi/x_twitter_scraper/models/x/account_connection_attempt_retrieve_response.rbi @@ -0,0 +1,317 @@ +# typed: strong + +module XTwitterScraper + module Models + module X + # The connection is still in progress. + module AccountConnectionAttemptRetrieveResponse + extend XTwitterScraper::Internal::Type::Union + + Variants = + T.type_alias do + T.any( + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptPending, + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptSuccess, + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptFailed, + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge + ) + end + + class XAccountConnectionAttemptPending < XTwitterScraper::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptPending, + XTwitterScraper::Internal::AnyHash + ) + end + + sig { returns(String) } + attr_accessor :id + + sig { returns(Symbol) } + attr_accessor :object + + sig { returns(Integer) } + attr_accessor :poll_after_ms + + sig { returns(Symbol) } + attr_accessor :status + + # The connection is still in progress. + sig do + params( + id: String, + poll_after_ms: Integer, + object: Symbol, + status: Symbol + ).returns(T.attached_class) + end + def self.new( + id:, + poll_after_ms:, + object: :x_account_connection_attempt, + status: :pending + ) + end + + sig do + override.returns( + { + id: String, + object: Symbol, + poll_after_ms: Integer, + status: Symbol + } + ) + end + def to_hash + end + end + + class XAccountConnectionAttemptSuccess < XTwitterScraper::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptSuccess, + XTwitterScraper::Internal::AnyHash + ) + end + + sig { returns(String) } + attr_accessor :id + + sig { returns(Symbol) } + attr_accessor :object + + sig { returns(Symbol) } + attr_accessor :status + + # The account connected successfully. + sig do + params(id: String, object: Symbol, status: Symbol).returns( + T.attached_class + ) + end + def self.new( + id:, + object: :x_account_connection_attempt, + status: :success + ) + end + + sig do + override.returns({ id: String, object: Symbol, status: Symbol }) + end + def to_hash + end + end + + class XAccountConnectionAttemptFailed < XTwitterScraper::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptFailed, + XTwitterScraper::Internal::AnyHash + ) + end + + sig { returns(String) } + attr_accessor :id + + sig { returns(String) } + attr_accessor :error + + sig { returns(Symbol) } + attr_accessor :object + + sig { returns(T::Boolean) } + attr_accessor :retryable + + sig { returns(Symbol) } + attr_accessor :status + + sig { returns(T.nilable(String)) } + attr_reader :reason + + sig { params(reason: String).void } + attr_writer :reason + + # The connection reached a final failure. + sig do + params( + id: String, + error: String, + retryable: T::Boolean, + reason: String, + object: Symbol, + status: Symbol + ).returns(T.attached_class) + end + def self.new( + id:, + error:, + retryable:, + reason: nil, + object: :x_account_connection_attempt, + status: :failed + ) + end + + sig do + override.returns( + { + id: String, + error: String, + object: Symbol, + retryable: T::Boolean, + status: Symbol, + reason: String + } + ) + end + def to_hash + end + end + + class XAccountConnectionChallenge < XTwitterScraper::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge, + XTwitterScraper::Internal::AnyHash + ) + end + + sig { returns(String) } + attr_accessor :id + + sig { returns(Time) } + attr_accessor :expires_at + + sig { returns(String) } + attr_accessor :message + + sig do + returns( + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Object::TaggedSymbol + ) + end + attr_accessor :object + + sig do + returns( + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Status::TaggedSymbol + ) + end + attr_accessor :status + + sig { returns(String) } + attr_accessor :username + + # Resumable account connection challenge. Submit the email code to finish the same + # connection attempt. + sig do + params( + id: String, + expires_at: Time, + message: String, + object: + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Object::OrSymbol, + status: + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Status::OrSymbol, + username: String + ).returns(T.attached_class) + end + def self.new(id:, expires_at:, message:, object:, status:, username:) + end + + sig do + override.returns( + { + id: String, + expires_at: Time, + message: String, + object: + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Object::TaggedSymbol, + status: + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Status::TaggedSymbol, + username: String + } + ) + end + def to_hash + end + + module Object + extend XTwitterScraper::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Object + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + X_ACCOUNT_CONNECTION_CHALLENGE = + T.let( + :x_account_connection_challenge, + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Object::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Object::TaggedSymbol + ] + ) + end + def self.values + end + end + + module Status + extend XTwitterScraper::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Status + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + REQUIRES_EMAIL_CODE = + T.let( + :requires_email_code, + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Status::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::Status::TaggedSymbol + ] + ) + end + def self.values + end + end + end + + sig do + override.returns( + T::Array[ + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::Variants + ] + ) + end + def self.variants + end + end + end + end +end diff --git a/rbi/x_twitter_scraper/models/x/account_create_params.rbi b/rbi/x_twitter_scraper/models/x/account_create_params.rbi index e885c94..3c5ef92 100644 --- a/rbi/x_twitter_scraper/models/x/account_create_params.rbi +++ b/rbi/x_twitter_scraper/models/x/account_create_params.rbi @@ -27,23 +27,20 @@ module XTwitterScraper sig { returns(String) } attr_accessor :password + # Authenticator App TOTP secret required for durable login + sig { returns(String) } + attr_accessor :totp_secret + # X username sig { returns(String) } attr_accessor :username - # TOTP secret for 2FA - sig { returns(T.nilable(String)) } - attr_reader :totp_secret - - sig { params(totp_secret: String).void } - attr_writer :totp_secret - sig do params( email: String, password: String, - username: String, totp_secret: String, + username: String, request_options: XTwitterScraper::RequestOptions::OrHash ).returns(T.attached_class) end @@ -52,10 +49,10 @@ module XTwitterScraper email:, # Account password password:, + # Authenticator App TOTP secret required for durable login + totp_secret:, # X username username:, - # TOTP secret for 2FA - totp_secret: nil, request_options: {} ) end @@ -65,8 +62,8 @@ module XTwitterScraper { email: String, password: String, - username: String, totp_secret: String, + username: String, request_options: XTwitterScraper::RequestOptions } ) diff --git a/rbi/x_twitter_scraper/models/x/account_create_response.rbi b/rbi/x_twitter_scraper/models/x/account_create_response.rbi index bc90c3b..b88eef7 100644 --- a/rbi/x_twitter_scraper/models/x/account_create_response.rbi +++ b/rbi/x_twitter_scraper/models/x/account_create_response.rbi @@ -7,129 +7,8 @@ module XTwitterScraper module Models module X - class AccountCreateResponse < XTwitterScraper::Internal::Type::BaseModel - OrHash = - T.type_alias do - T.any( - XTwitterScraper::Models::X::AccountCreateResponse, - XTwitterScraper::Internal::AnyHash - ) - end - - sig { returns(String) } - attr_accessor :id - - sig { returns(Time) } - attr_accessor :created_at - - sig do - returns( - XTwitterScraper::Models::X::AccountCreateResponse::Health::TaggedSymbol - ) - end - attr_accessor :health - - sig { returns(String) } - attr_accessor :status - - sig { returns(String) } - attr_accessor :x_user_id - - sig { returns(String) } - attr_accessor :x_username - - # Sanitized X account summary returned by connect and reauth. - sig do - params( - id: String, - created_at: Time, - health: - XTwitterScraper::Models::X::AccountCreateResponse::Health::OrSymbol, - status: String, - x_user_id: String, - x_username: String - ).returns(T.attached_class) - end - def self.new( - id:, - created_at:, - health:, - status:, - x_user_id:, - x_username: - ) - end - - sig do - override.returns( - { - id: String, - created_at: Time, - health: - XTwitterScraper::Models::X::AccountCreateResponse::Health::TaggedSymbol, - status: String, - x_user_id: String, - x_username: String - } - ) - end - def to_hash - end - - module Health - extend XTwitterScraper::Internal::Type::Enum - - TaggedSymbol = - T.type_alias do - T.all( - Symbol, - XTwitterScraper::Models::X::AccountCreateResponse::Health - ) - end - OrSymbol = T.type_alias { T.any(Symbol, String) } - - HEALTHY = - T.let( - :healthy, - XTwitterScraper::Models::X::AccountCreateResponse::Health::TaggedSymbol - ) - LOCKED = - T.let( - :locked, - XTwitterScraper::Models::X::AccountCreateResponse::Health::TaggedSymbol - ) - NEEDS_REAUTH = - T.let( - :needsReauth, - XTwitterScraper::Models::X::AccountCreateResponse::Health::TaggedSymbol - ) - RECOVERING = - T.let( - :recovering, - XTwitterScraper::Models::X::AccountCreateResponse::Health::TaggedSymbol - ) - SUSPENDED = - T.let( - :suspended, - XTwitterScraper::Models::X::AccountCreateResponse::Health::TaggedSymbol - ) - TEMPORARY_ISSUE = - T.let( - :temporaryIssue, - XTwitterScraper::Models::X::AccountCreateResponse::Health::TaggedSymbol - ) - - sig do - override.returns( - T::Array[ - XTwitterScraper::Models::X::AccountCreateResponse::Health::TaggedSymbol - ] - ) - end - def self.values - end - end - end + AccountCreateResponse = + T.let(T.anything, XTwitterScraper::Internal::Type::Converter) end end end diff --git a/rbi/x_twitter_scraper/models/x/account_reauth_params.rbi b/rbi/x_twitter_scraper/models/x/account_reauth_params.rbi index dd3ba78..ff84c4f 100644 --- a/rbi/x_twitter_scraper/models/x/account_reauth_params.rbi +++ b/rbi/x_twitter_scraper/models/x/account_reauth_params.rbi @@ -33,7 +33,7 @@ module XTwitterScraper sig { params(email: String).void } attr_writer :email - # TOTP secret for 2FA re-authentication + # Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret. sig { returns(T.nilable(String)) } attr_reader :totp_secret @@ -55,7 +55,7 @@ module XTwitterScraper password:, # Email for the X account (updates stored email) email: nil, - # TOTP secret for 2FA re-authentication + # Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret. totp_secret: nil, request_options: {} ) diff --git a/rbi/x_twitter_scraper/models/x/x_account.rbi b/rbi/x_twitter_scraper/models/x/x_account.rbi index c7e2ff4..66664eb 100644 --- a/rbi/x_twitter_scraper/models/x/x_account.rbi +++ b/rbi/x_twitter_scraper/models/x/x_account.rbi @@ -24,11 +24,11 @@ module XTwitterScraper sig { returns(Time) } attr_accessor :created_at - # Derived connection health. `healthy` = session active. `needsReauth` = user must + # Derived connection health. `healthy` = ready to use. `needsReauth` = user must # submit fresh credentials. `locked` = X locked the account; unlock on x.com - # first. `suspended` = X banned the account. `recovering` = past cooldown, will - # auto-retry on next use. `temporaryIssue` = temporary connection problem; retry - # shortly. + # first. `suspended` = X banned the account. `recovering` = cooldown ended; the + # account can reconnect on its next use. `temporaryIssue` = temporary connection + # problem; wait before the next use. sig { returns(XTwitterScraper::X::XAccount::Health::TaggedSymbol) } attr_accessor :health @@ -66,11 +66,11 @@ module XTwitterScraper def self.new( id:, created_at:, - # Derived connection health. `healthy` = session active. `needsReauth` = user must + # Derived connection health. `healthy` = ready to use. `needsReauth` = user must # submit fresh credentials. `locked` = X locked the account; unlock on x.com - # first. `suspended` = X banned the account. `recovering` = past cooldown, will - # auto-retry on next use. `temporaryIssue` = temporary connection problem; retry - # shortly. + # first. `suspended` = X banned the account. `recovering` = cooldown ended; the + # account can reconnect on its next use. `temporaryIssue` = temporary connection + # problem; wait before the next use. health:, status:, updated_at:, @@ -97,11 +97,11 @@ module XTwitterScraper def to_hash end - # Derived connection health. `healthy` = session active. `needsReauth` = user must + # Derived connection health. `healthy` = ready to use. `needsReauth` = user must # submit fresh credentials. `locked` = X locked the account; unlock on x.com - # first. `suspended` = X banned the account. `recovering` = past cooldown, will - # auto-retry on next use. `temporaryIssue` = temporary connection problem; retry - # shortly. + # first. `suspended` = X banned the account. `recovering` = cooldown ended; the + # account can reconnect on its next use. `temporaryIssue` = temporary connection + # problem; wait before the next use. module Health extend XTwitterScraper::Internal::Type::Enum diff --git a/rbi/x_twitter_scraper/resources/compose.rbi b/rbi/x_twitter_scraper/resources/compose.rbi index c825caa..c52a053 100644 --- a/rbi/x_twitter_scraper/resources/compose.rbi +++ b/rbi/x_twitter_scraper/resources/compose.rbi @@ -8,10 +8,10 @@ module XTwitterScraper module Resources # AI tweet composition, drafts, writing styles, and radar class Compose - # Run one step of Xquik's three-step writing workflow. Compose returns questions - # and editorial rules. Refine returns goal-specific guidance. Score applies - # deterministic text checks. It does not predict reach or expose X ranking - # weights. + # Run one step of Xquik's three-step writing workflow. Compose returns questions, + # editorial rules, and source-specific Radar recommendations. Refine returns + # goal-specific guidance. Score applies deterministic text checks. It does not + # predict reach or expose X ranking weights. sig do params( body: diff --git a/rbi/x_twitter_scraper/resources/x.rbi b/rbi/x_twitter_scraper/resources/x.rbi index 0f20957..c683299 100644 --- a/rbi/x_twitter_scraper/resources/x.rbi +++ b/rbi/x_twitter_scraper/resources/x.rbi @@ -44,6 +44,10 @@ module XTwitterScraper end attr_reader :account_connection_challenges + # Connected X account management + sig { returns(XTwitterScraper::Resources::X::AccountConnectionAttempts) } + attr_reader :account_connection_attempts + # Look up, search, and analyze individual tweets sig { returns(XTwitterScraper::Resources::X::Bookmarks) } attr_reader :bookmarks diff --git a/rbi/x_twitter_scraper/resources/x/account_connection_attempts.rbi b/rbi/x_twitter_scraper/resources/x/account_connection_attempts.rbi new file mode 100644 index 0000000..74b0d79 --- /dev/null +++ b/rbi/x_twitter_scraper/resources/x/account_connection_attempts.rbi @@ -0,0 +1,33 @@ +# typed: strong + +module XTwitterScraper + module Resources + class X + # Connected X account management + class AccountConnectionAttempts + # Get X account connection status + sig do + params( + id: String, + request_options: XTwitterScraper::RequestOptions::OrHash + ).returns( + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::Variants + ) + end + def retrieve( + # Connection attempt ID returned by `POST /x/accounts`. + id, + request_options: {} + ) + end + + # @api private + sig do + params(client: XTwitterScraper::Client).returns(T.attached_class) + end + def self.new(client:) + end + end + end + end +end diff --git a/rbi/x_twitter_scraper/resources/x/accounts.rbi b/rbi/x_twitter_scraper/resources/x/accounts.rbi index 1709455..41742a8 100644 --- a/rbi/x_twitter_scraper/resources/x/accounts.rbi +++ b/rbi/x_twitter_scraper/resources/x/accounts.rbi @@ -14,20 +14,20 @@ module XTwitterScraper params( email: String, password: String, - username: String, totp_secret: String, + username: String, request_options: XTwitterScraper::RequestOptions::OrHash - ).returns(XTwitterScraper::Models::X::AccountCreateResponse) + ).returns(T.anything) end def create( # Account email email:, # Account password password:, + # Authenticator App TOTP secret required for durable login + totp_secret:, # X username username:, - # TOTP secret for 2FA - totp_secret: nil, request_options: {} ) end @@ -96,7 +96,7 @@ module XTwitterScraper password:, # Email for the X account (updates stored email) email: nil, - # TOTP secret for 2FA re-authentication + # Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret. totp_secret: nil, request_options: {} ) diff --git a/sig/x_twitter_scraper/models/compose_create_response.rbs b/sig/x_twitter_scraper/models/compose_create_response.rbs index 44aea65..193c4b6 100644 --- a/sig/x_twitter_scraper/models/compose_create_response.rbs +++ b/sig/x_twitter_scraper/models/compose_create_response.rbs @@ -20,6 +20,7 @@ module XTwitterScraper follow_up_questions: ::Array[String], intent_url: String, next_step: String, + radar_recommendations: ::Array[XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation], scorer_weights: ::Array[XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::ScorerWeight], source: String, top_penalties: ::Array[String], @@ -41,6 +42,8 @@ module XTwitterScraper attr_accessor next_step: String + attr_accessor radar_recommendations: ::Array[XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation] + attr_accessor scorer_weights: ::Array[XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::ScorerWeight] attr_accessor source: String @@ -68,6 +71,7 @@ module XTwitterScraper follow_up_questions: ::Array[String], intent_url: String, next_step: String, + radar_recommendations: ::Array[XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation], scorer_weights: ::Array[XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::ScorerWeight], source: String, top_penalties: ::Array[String], @@ -83,6 +87,7 @@ module XTwitterScraper follow_up_questions: ::Array[String], intent_url: String, next_step: String, + radar_recommendations: ::Array[XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation], scorer_weights: ::Array[XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::ScorerWeight], source: String, top_penalties: ::Array[String], @@ -123,6 +128,61 @@ module XTwitterScraper } end + type radar_recommendation = + { + endpoint: String, + guidance: String, + source: XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::source, + use_for: String + } + + class RadarRecommendation < XTwitterScraper::Internal::Type::BaseModel + attr_accessor endpoint: String + + attr_accessor guidance: String + + attr_accessor source: XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::source + + attr_accessor use_for: String + + def initialize: ( + endpoint: String, + guidance: String, + source: XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::source, + use_for: String + ) -> void + + def to_hash: -> { + endpoint: String, + guidance: String, + source: XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::source, + use_for: String + } + + type source = + :reddit + | :github + | :trustmrr + | :hacker_news + | :google_trends + | :wikipedia + | :polymarket + + module Source + extend XTwitterScraper::Internal::Type::Enum + + REDDIT: :reddit + GITHUB: :github + TRUSTMRR: :trustmrr + HACKER_NEWS: :hacker_news + GOOGLE_TRENDS: :google_trends + WIKIPEDIA: :wikipedia + POLYMARKET: :polymarket + + def self?.values: -> ::Array[XTwitterScraper::Models::ComposeCreateResponse::ComposePrepareResult::RadarRecommendation::source] + end + end + type scorer_weight = { context: String, signal: String, weight: nil } class ScorerWeight < XTwitterScraper::Internal::Type::BaseModel diff --git a/sig/x_twitter_scraper/models/radar_item.rbs b/sig/x_twitter_scraper/models/radar_item.rbs index 2976c68..33793ef 100644 --- a/sig/x_twitter_scraper/models/radar_item.rbs +++ b/sig/x_twitter_scraper/models/radar_item.rbs @@ -10,7 +10,7 @@ module XTwitterScraper category: XTwitterScraper::Models::RadarItem::category, created_at: Time, language: String, - metadata: ::Hash[Symbol, top], + metadata: XTwitterScraper::RadarItem::Metadata, published_at: Time, region: String, score: Float, @@ -31,7 +31,7 @@ module XTwitterScraper attr_accessor language: String - attr_accessor metadata: ::Hash[Symbol, top] + attr_accessor metadata: XTwitterScraper::RadarItem::Metadata attr_accessor published_at: Time @@ -62,7 +62,7 @@ module XTwitterScraper category: XTwitterScraper::Models::RadarItem::category, created_at: Time, language: String, - metadata: ::Hash[Symbol, top], + metadata: XTwitterScraper::RadarItem::Metadata, published_at: Time, region: String, score: Float, @@ -79,7 +79,7 @@ module XTwitterScraper category: XTwitterScraper::Models::RadarItem::category, created_at: Time, language: String, - metadata: ::Hash[Symbol, top], + metadata: XTwitterScraper::RadarItem::Metadata, published_at: Time, region: String, score: Float, @@ -116,6 +116,102 @@ module XTwitterScraper def self?.values: -> ::Array[XTwitterScraper::Models::RadarItem::category] end + type metadata = + { + author: String, + content_url: String, + estimated_downvotes: Integer, + estimated_upvotes: Integer, + number_comments: Integer, + score: Integer, + selftext: String, + source_format: XTwitterScraper::Models::RadarItem::Metadata::source_format, + subreddit: String, + upvote_ratio: Float + } + + class Metadata < XTwitterScraper::Internal::Type::BaseModel + attr_reader author: String? + + def author=: (String) -> String + + attr_reader content_url: String? + + def content_url=: (String) -> String + + attr_reader estimated_downvotes: Integer? + + def estimated_downvotes=: (Integer) -> Integer + + attr_reader estimated_upvotes: Integer? + + def estimated_upvotes=: (Integer) -> Integer + + attr_reader number_comments: Integer? + + def number_comments=: (Integer) -> Integer + + attr_reader score: Integer? + + def score=: (Integer) -> Integer + + attr_reader selftext: String? + + def selftext=: (String) -> String + + attr_reader source_format: XTwitterScraper::Models::RadarItem::Metadata::source_format? + + def source_format=: ( + XTwitterScraper::Models::RadarItem::Metadata::source_format + ) -> XTwitterScraper::Models::RadarItem::Metadata::source_format + + attr_reader subreddit: String? + + def subreddit=: (String) -> String + + attr_reader upvote_ratio: Float? + + def upvote_ratio=: (Float) -> Float + + def initialize: ( + ?author: String, + ?content_url: String, + ?estimated_downvotes: Integer, + ?estimated_upvotes: Integer, + ?number_comments: Integer, + ?score: Integer, + ?selftext: String, + ?source_format: XTwitterScraper::Models::RadarItem::Metadata::source_format, + ?subreddit: String, + ?upvote_ratio: Float + ) -> void + + def to_hash: -> { + author: String, + content_url: String, + estimated_downvotes: Integer, + estimated_upvotes: Integer, + number_comments: Integer, + score: Integer, + selftext: String, + source_format: XTwitterScraper::Models::RadarItem::Metadata::source_format, + subreddit: String, + upvote_ratio: Float + } + + type source_format = :html | :json | :rss + + module SourceFormat + extend XTwitterScraper::Internal::Type::Enum + + HTML: :html + JSON: :json + RSS: :rss + + def self?.values: -> ::Array[XTwitterScraper::Models::RadarItem::Metadata::source_format] + end + end + type source = :github | :google_trends diff --git a/sig/x_twitter_scraper/models/x/account_connection_attempt_retrieve_params.rbs b/sig/x_twitter_scraper/models/x/account_connection_attempt_retrieve_params.rbs new file mode 100644 index 0000000..ec913c6 --- /dev/null +++ b/sig/x_twitter_scraper/models/x/account_connection_attempt_retrieve_params.rbs @@ -0,0 +1,25 @@ +module XTwitterScraper + module Models + module X + type account_connection_attempt_retrieve_params = + { id: String } & XTwitterScraper::Internal::Type::request_parameters + + class AccountConnectionAttemptRetrieveParams < XTwitterScraper::Internal::Type::BaseModel + extend XTwitterScraper::Internal::Type::RequestParameters::Converter + include XTwitterScraper::Internal::Type::RequestParameters + + attr_accessor id: String + + def initialize: ( + id: String, + ?request_options: XTwitterScraper::request_opts + ) -> void + + def to_hash: -> { + id: String, + request_options: XTwitterScraper::RequestOptions + } + end + end + end +end diff --git a/sig/x_twitter_scraper/models/x/account_connection_attempt_retrieve_response.rbs b/sig/x_twitter_scraper/models/x/account_connection_attempt_retrieve_response.rbs new file mode 100644 index 0000000..06ceb79 --- /dev/null +++ b/sig/x_twitter_scraper/models/x/account_connection_attempt_retrieve_response.rbs @@ -0,0 +1,182 @@ +module XTwitterScraper + module Models + module X + type account_connection_attempt_retrieve_response = + XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptPending + | XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptSuccess + | XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptFailed + | XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge + + module AccountConnectionAttemptRetrieveResponse + extend XTwitterScraper::Internal::Type::Union + + type x_account_connection_attempt_pending = + { + id: String, + object: :x_account_connection_attempt, + poll_after_ms: Integer, + status: :pending + } + + class XAccountConnectionAttemptPending < XTwitterScraper::Internal::Type::BaseModel + attr_accessor id: String + + attr_accessor object: :x_account_connection_attempt + + attr_accessor poll_after_ms: Integer + + attr_accessor status: :pending + + def initialize: ( + id: String, + poll_after_ms: Integer, + ?object: :x_account_connection_attempt, + ?status: :pending + ) -> void + + def to_hash: -> { + id: String, + object: :x_account_connection_attempt, + poll_after_ms: Integer, + status: :pending + } + end + + type x_account_connection_attempt_success = + { + id: String, + object: :x_account_connection_attempt, + status: :success + } + + class XAccountConnectionAttemptSuccess < XTwitterScraper::Internal::Type::BaseModel + attr_accessor id: String + + attr_accessor object: :x_account_connection_attempt + + attr_accessor status: :success + + def initialize: ( + id: String, + ?object: :x_account_connection_attempt, + ?status: :success + ) -> void + + def to_hash: -> { + id: String, + object: :x_account_connection_attempt, + status: :success + } + end + + type x_account_connection_attempt_failed = + { + id: String, + error: String, + object: :x_account_connection_attempt, + retryable: bool, + status: :failed, + reason: String + } + + class XAccountConnectionAttemptFailed < XTwitterScraper::Internal::Type::BaseModel + attr_accessor id: String + + attr_accessor error: String + + attr_accessor object: :x_account_connection_attempt + + attr_accessor retryable: bool + + attr_accessor status: :failed + + attr_reader reason: String? + + def reason=: (String) -> String + + def initialize: ( + id: String, + error: String, + retryable: bool, + ?reason: String, + ?object: :x_account_connection_attempt, + ?status: :failed + ) -> void + + def to_hash: -> { + id: String, + error: String, + object: :x_account_connection_attempt, + retryable: bool, + status: :failed, + reason: String + } + end + + type x_account_connection_challenge = + { + id: String, + expires_at: Time, + message: String, + object: XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::object, + status: XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::status, + username: String + } + + class XAccountConnectionChallenge < XTwitterScraper::Internal::Type::BaseModel + attr_accessor id: String + + attr_accessor expires_at: Time + + attr_accessor message: String + + attr_accessor object: XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::object + + attr_accessor status: XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::status + + attr_accessor username: String + + def initialize: ( + id: String, + expires_at: Time, + message: String, + object: XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::object, + status: XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::status, + username: String + ) -> void + + def to_hash: -> { + id: String, + expires_at: Time, + message: String, + object: XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::object, + status: XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::status, + username: String + } + + type object = :x_account_connection_challenge + + module Object + extend XTwitterScraper::Internal::Type::Enum + + X_ACCOUNT_CONNECTION_CHALLENGE: :x_account_connection_challenge + + def self?.values: -> ::Array[XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::object] + end + + type status = :requires_email_code + + module Status + extend XTwitterScraper::Internal::Type::Enum + + REQUIRES_EMAIL_CODE: :requires_email_code + + def self?.values: -> ::Array[XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge::status] + end + end + + def self?.variants: -> ::Array[XTwitterScraper::Models::X::account_connection_attempt_retrieve_response] + end + end + end +end diff --git a/sig/x_twitter_scraper/models/x/account_create_params.rbs b/sig/x_twitter_scraper/models/x/account_create_params.rbs index 1c0089e..e06a0e0 100644 --- a/sig/x_twitter_scraper/models/x/account_create_params.rbs +++ b/sig/x_twitter_scraper/models/x/account_create_params.rbs @@ -9,8 +9,8 @@ module XTwitterScraper { email: String, password: String, - username: String, - totp_secret: String + totp_secret: String, + username: String } & XTwitterScraper::Internal::Type::request_parameters @@ -22,25 +22,23 @@ module XTwitterScraper attr_accessor password: String - attr_accessor username: String - - attr_reader totp_secret: String? + attr_accessor totp_secret: String - def totp_secret=: (String) -> String + attr_accessor username: String def initialize: ( email: String, password: String, + totp_secret: String, username: String, - ?totp_secret: String, ?request_options: XTwitterScraper::request_opts ) -> void def to_hash: -> { email: String, password: String, - username: String, totp_secret: String, + username: String, request_options: XTwitterScraper::RequestOptions } end diff --git a/sig/x_twitter_scraper/models/x/account_create_response.rbs b/sig/x_twitter_scraper/models/x/account_create_response.rbs index 7f52142..60ab61e 100644 --- a/sig/x_twitter_scraper/models/x/account_create_response.rbs +++ b/sig/x_twitter_scraper/models/x/account_create_response.rbs @@ -5,68 +5,7 @@ module XTwitterScraper module Models module X - type account_create_response = - { - id: String, - created_at: Time, - health: XTwitterScraper::Models::X::AccountCreateResponse::health, - status: String, - x_user_id: String, - x_username: String - } - - class AccountCreateResponse < XTwitterScraper::Internal::Type::BaseModel - attr_accessor id: String - - attr_accessor created_at: Time - - attr_accessor health: XTwitterScraper::Models::X::AccountCreateResponse::health - - attr_accessor status: String - - attr_accessor x_user_id: String - - attr_accessor x_username: String - - def initialize: ( - id: String, - created_at: Time, - health: XTwitterScraper::Models::X::AccountCreateResponse::health, - status: String, - x_user_id: String, - x_username: String - ) -> void - - def to_hash: -> { - id: String, - created_at: Time, - health: XTwitterScraper::Models::X::AccountCreateResponse::health, - status: String, - x_user_id: String, - x_username: String - } - - type health = - :healthy - | :locked - | :needsReauth - | :recovering - | :suspended - | :temporaryIssue - - module Health - extend XTwitterScraper::Internal::Type::Enum - - HEALTHY: :healthy - LOCKED: :locked - NEEDS_REAUTH: :needsReauth - RECOVERING: :recovering - SUSPENDED: :suspended - TEMPORARY_ISSUE: :temporaryIssue - - def self?.values: -> ::Array[XTwitterScraper::Models::X::AccountCreateResponse::health] - end - end + AccountCreateResponse: XTwitterScraper::Internal::Type::Converter end end end diff --git a/sig/x_twitter_scraper/resources/x.rbs b/sig/x_twitter_scraper/resources/x.rbs index a5f54d9..36ba897 100644 --- a/sig/x_twitter_scraper/resources/x.rbs +++ b/sig/x_twitter_scraper/resources/x.rbs @@ -25,6 +25,8 @@ module XTwitterScraper attr_reader account_connection_challenges: XTwitterScraper::Resources::X::AccountConnectionChallenges + attr_reader account_connection_attempts: XTwitterScraper::Resources::X::AccountConnectionAttempts + attr_reader bookmarks: XTwitterScraper::Resources::X::Bookmarks attr_reader lists: XTwitterScraper::Resources::X::Lists diff --git a/sig/x_twitter_scraper/resources/x/account_connection_attempts.rbs b/sig/x_twitter_scraper/resources/x/account_connection_attempts.rbs new file mode 100644 index 0000000..1d3c080 --- /dev/null +++ b/sig/x_twitter_scraper/resources/x/account_connection_attempts.rbs @@ -0,0 +1,14 @@ +module XTwitterScraper + module Resources + class X + class AccountConnectionAttempts + def retrieve: ( + String id, + ?request_options: XTwitterScraper::request_opts + ) -> XTwitterScraper::Models::X::account_connection_attempt_retrieve_response + + def initialize: (client: XTwitterScraper::Client) -> void + end + end + end +end diff --git a/sig/x_twitter_scraper/resources/x/accounts.rbs b/sig/x_twitter_scraper/resources/x/accounts.rbs index 7848412..96ce1d9 100644 --- a/sig/x_twitter_scraper/resources/x/accounts.rbs +++ b/sig/x_twitter_scraper/resources/x/accounts.rbs @@ -9,10 +9,10 @@ module XTwitterScraper def create: ( email: String, password: String, + totp_secret: String, username: String, - ?totp_secret: String, ?request_options: XTwitterScraper::request_opts - ) -> XTwitterScraper::Models::X::AccountCreateResponse + ) -> top def retrieve: ( String id, diff --git a/test/x_twitter_scraper/resources/x/account_connection_attempts_test.rb b/test/x_twitter_scraper/resources/x/account_connection_attempts_test.rb new file mode 100644 index 0000000..cc0310d --- /dev/null +++ b/test/x_twitter_scraper/resources/x/account_connection_attempts_test.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require_relative "../../test_helper" + +class XTwitterScraper::Test::Resources::X::AccountConnectionAttemptsTest < XTwitterScraper::Test::ResourceTest + def test_retrieve + skip("Mock server tests are disabled") + + response = + @x_twitter_scraper.x.account_connection_attempts.retrieve("xatt_0123456789abcdef0123456789abcdef") + + assert_pattern do + response => XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse + end + + assert_pattern do + case response + in XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptPending + in XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptSuccess + in XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionAttemptFailed + in XTwitterScraper::Models::X::AccountConnectionAttemptRetrieveResponse::XAccountConnectionChallenge + end + end + end +end diff --git a/test/x_twitter_scraper/resources/x/accounts_test.rb b/test/x_twitter_scraper/resources/x/accounts_test.rb index 58e337e..35d7cd1 100644 --- a/test/x_twitter_scraper/resources/x/accounts_test.rb +++ b/test/x_twitter_scraper/resources/x/accounts_test.rb @@ -12,22 +12,12 @@ def test_create_required_params @x_twitter_scraper.x.accounts.create( email: "account@example.invalid", password: "", + totp_secret: "", username: "your_x_username" ) assert_pattern do - response => XTwitterScraper::Models::X::AccountCreateResponse - end - - assert_pattern do - response => { - id: String, - created_at: Time, - health: XTwitterScraper::Models::X::AccountCreateResponse::Health, - status: String, - x_user_id: String, - x_username: String - } + response => XTwitterScraper::Internal::Type::Unknown end end