diff --git a/.release-please-manifest.json b/.release-please-manifest.json index bf5f1fb..e7ca613 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.6.2" + ".": "0.7.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 ebd98f9..3647c17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.7.0 (2026-07-29) + +Full Changelog: [v0.6.2...v0.7.0](https://github.com/Xquik-dev/x-twitter-scraper-java/compare/v0.6.2...v0.7.0) + +### Features + +* **api:** api update ([6279df5](https://github.com/Xquik-dev/x-twitter-scraper-java/commit/6279df51bebd8d2b2896ed4139259a01ca8f03e7)) +* **api:** api update ([5609e87](https://github.com/Xquik-dev/x-twitter-scraper-java/commit/5609e87e446ee8de9026d6dc418de1bd9945e3e9)) + ## 0.6.2 (2026-07-28) Full Changelog: [v0.6.1...v0.6.2](https://github.com/Xquik-dev/x-twitter-scraper-java/compare/v0.6.1...v0.6.2) diff --git a/README.md b/README.md index 98dd6cc..6e01c01 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ Use it as a typed X API or Twitter API alternative. -[![Maven Central](https://img.shields.io/maven-central/v/com.xquik.api/x-twitter-scraper-java)](https://central.sonatype.com/artifact/com.xquik.api/x-twitter-scraper-java/0.6.2) -[![Javadocs](https://javadoc.io/badge2/com.xquik.api/x-twitter-scraper-java/0.6.2/javadoc.svg)](https://javadoc.io/doc/com.xquik.api/x-twitter-scraper-java/0.6.2) +[![Maven Central](https://img.shields.io/maven-central/v/com.xquik.api/x-twitter-scraper-java)](https://central.sonatype.com/artifact/com.xquik.api/x-twitter-scraper-java/0.7.0) +[![Javadocs](https://javadoc.io/badge2/com.xquik.api/x-twitter-scraper-java/0.7.0/javadoc.svg)](https://javadoc.io/doc/com.xquik.api/x-twitter-scraper-java/0.7.0) @@ -64,7 +64,7 @@ Use [API reference](https://docs.xquik.com/api-reference/overview) for request c Gradle: ```kotlin -implementation("com.xquik.api:x-twitter-scraper-java:0.6.2") +implementation("com.xquik.api:x-twitter-scraper-java:0.7.0") ``` Maven: @@ -73,7 +73,7 @@ Maven: com.xquik.api x-twitter-scraper-java - 0.6.2 + 0.7.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index 5f5bf44..d96eadf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -36,7 +36,7 @@ licenseReport { allprojects { group = "com.xquik.api" - version = "0.6.2" // x-release-please-version + version = "0.7.0" // x-release-please-version dependencyLocking { lockAllConfigurations() diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/compose/ComposeCreateParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/compose/ComposeCreateParams.kt index 9565520..c8342d9 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/compose/ComposeCreateParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/compose/ComposeCreateParams.kt @@ -37,9 +37,9 @@ import java.util.Optional import kotlin.jvm.optionals.getOrNull /** - * 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. */ class ComposeCreateParams private constructor( diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/compose/ComposeCreateResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/compose/ComposeCreateResponse.kt index 45b3233..8512137 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/compose/ComposeCreateResponse.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/compose/ComposeCreateResponse.kt @@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.x_twitter_scraper.api.core.BaseDeserializer import com.x_twitter_scraper.api.core.BaseSerializer +import com.x_twitter_scraper.api.core.Enum import com.x_twitter_scraper.api.core.ExcludeMissing import com.x_twitter_scraper.api.core.JsonField import com.x_twitter_scraper.api.core.JsonMissing @@ -288,6 +289,7 @@ private constructor( private val followUpQuestions: JsonField>, private val intentUrl: JsonField, private val nextStep: JsonField, + private val radarRecommendations: JsonField>, private val scorerWeights: JsonField>, private val source: JsonField, private val topPenalties: JsonField>, @@ -317,6 +319,9 @@ private constructor( @JsonProperty("nextStep") @ExcludeMissing nextStep: JsonField = JsonMissing.of(), + @JsonProperty("radarRecommendations") + @ExcludeMissing + radarRecommendations: JsonField> = JsonMissing.of(), @JsonProperty("scorerWeights") @ExcludeMissing scorerWeights: JsonField> = JsonMissing.of(), @@ -340,6 +345,7 @@ private constructor( followUpQuestions, intentUrl, nextStep, + radarRecommendations, scorerWeights, source, topPenalties, @@ -400,6 +406,16 @@ private constructor( */ fun nextStep(): String = nextStep.getRequired("nextStep") + /** + * Sources and guidance for researching a fresh post angle. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun radarRecommendations(): List = + radarRecommendations.getRequired("radarRecommendations") + /** * Published signal names with unpublished weights as null. * @@ -505,6 +521,16 @@ private constructor( */ @JsonProperty("nextStep") @ExcludeMissing fun _nextStep(): JsonField = nextStep + /** + * Returns the raw JSON value of [radarRecommendations]. + * + * Unlike [radarRecommendations], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("radarRecommendations") + @ExcludeMissing + fun _radarRecommendations(): JsonField> = radarRecommendations + /** * Returns the raw JSON value of [scorerWeights]. * @@ -582,6 +608,7 @@ private constructor( * .followUpQuestions() * .intentUrl() * .nextStep() + * .radarRecommendations() * .scorerWeights() * .source() * .topPenalties() @@ -599,6 +626,7 @@ private constructor( private var followUpQuestions: JsonField>? = null private var intentUrl: JsonField? = null private var nextStep: JsonField? = null + private var radarRecommendations: JsonField>? = null private var scorerWeights: JsonField>? = null private var source: JsonField? = null private var topPenalties: JsonField>? = null @@ -617,6 +645,8 @@ private constructor( composePrepareResult.followUpQuestions.map { it.toMutableList() } intentUrl = composePrepareResult.intentUrl nextStep = composePrepareResult.nextStep + radarRecommendations = + composePrepareResult.radarRecommendations.map { it.toMutableList() } scorerWeights = composePrepareResult.scorerWeights.map { it.toMutableList() } source = composePrepareResult.source topPenalties = composePrepareResult.topPenalties.map { it.toMutableList() } @@ -746,6 +776,34 @@ private constructor( */ fun nextStep(nextStep: JsonField) = apply { this.nextStep = nextStep } + /** Sources and guidance for researching a fresh post angle. */ + fun radarRecommendations(radarRecommendations: List) = + radarRecommendations(JsonField.of(radarRecommendations)) + + /** + * Sets [Builder.radarRecommendations] to an arbitrary JSON value. + * + * You should usually call [Builder.radarRecommendations] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun radarRecommendations(radarRecommendations: JsonField>) = + apply { + this.radarRecommendations = radarRecommendations.map { it.toMutableList() } + } + + /** + * Adds a single [RadarRecommendation] to [radarRecommendations]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRadarRecommendation(radarRecommendation: RadarRecommendation) = apply { + radarRecommendations = + (radarRecommendations ?: JsonField.of(mutableListOf())).also { + checkKnown("radarRecommendations", it).add(radarRecommendation) + } + } + /** Published signal names with unpublished weights as null. */ fun scorerWeights(scorerWeights: List) = scorerWeights(JsonField.of(scorerWeights)) @@ -907,6 +965,7 @@ private constructor( * .followUpQuestions() * .intentUrl() * .nextStep() + * .radarRecommendations() * .scorerWeights() * .source() * .topPenalties() @@ -924,6 +983,9 @@ private constructor( checkRequired("followUpQuestions", followUpQuestions).map { it.toImmutable() }, checkRequired("intentUrl", intentUrl), checkRequired("nextStep", nextStep), + checkRequired("radarRecommendations", radarRecommendations).map { + it.toImmutable() + }, checkRequired("scorerWeights", scorerWeights).map { it.toImmutable() }, checkRequired("source", source), checkRequired("topPenalties", topPenalties).map { it.toImmutable() }, @@ -956,6 +1018,7 @@ private constructor( followUpQuestions() intentUrl() nextStep() + radarRecommendations().forEach { it.validate() } scorerWeights().forEach { it.validate() } source() topPenalties() @@ -987,6 +1050,7 @@ private constructor( (followUpQuestions.asKnown().getOrNull()?.size ?: 0) + (if (intentUrl.asKnown().isPresent) 1 else 0) + (if (nextStep.asKnown().isPresent) 1 else 0) + + (radarRecommendations.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + (scorerWeights.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + (if (source.asKnown().isPresent) 1 else 0) + (topPenalties.asKnown().getOrNull()?.size ?: 0) + @@ -1384,6 +1448,475 @@ private constructor( "EngagementMultiplier{action=$action, multiplier=$multiplier, additionalProperties=$additionalProperties}" } + class RadarRecommendation + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val endpoint: JsonField, + private val guidance: JsonField, + private val source: JsonField, + private val useFor: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("endpoint") + @ExcludeMissing + endpoint: JsonField = JsonMissing.of(), + @JsonProperty("guidance") + @ExcludeMissing + guidance: JsonField = JsonMissing.of(), + @JsonProperty("source") + @ExcludeMissing + source: JsonField = JsonMissing.of(), + @JsonProperty("useFor") + @ExcludeMissing + useFor: JsonField = JsonMissing.of(), + ) : this(endpoint, guidance, source, useFor, mutableMapOf()) + + /** + * Radar endpoint for this source. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun endpoint(): String = endpoint.getRequired("endpoint") + + /** + * Source-specific drafting guidance. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun guidance(): String = guidance.getRequired("guidance") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun source(): Source = source.getRequired("source") + + /** + * Current-topic research this source supports. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun useFor(): String = useFor.getRequired("useFor") + + /** + * Returns the raw JSON value of [endpoint]. + * + * Unlike [endpoint], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("endpoint") @ExcludeMissing fun _endpoint(): JsonField = endpoint + + /** + * Returns the raw JSON value of [guidance]. + * + * Unlike [guidance], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("guidance") @ExcludeMissing fun _guidance(): JsonField = guidance + + /** + * Returns the raw JSON value of [source]. + * + * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source + + /** + * Returns the raw JSON value of [useFor]. + * + * Unlike [useFor], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("useFor") @ExcludeMissing fun _useFor(): JsonField = useFor + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [RadarRecommendation]. + * + * The following fields are required: + * ```java + * .endpoint() + * .guidance() + * .source() + * .useFor() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [RadarRecommendation]. */ + class Builder internal constructor() { + + private var endpoint: JsonField? = null + private var guidance: JsonField? = null + private var source: JsonField? = null + private var useFor: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(radarRecommendation: RadarRecommendation) = apply { + endpoint = radarRecommendation.endpoint + guidance = radarRecommendation.guidance + source = radarRecommendation.source + useFor = radarRecommendation.useFor + additionalProperties = radarRecommendation.additionalProperties.toMutableMap() + } + + /** Radar endpoint for this source. */ + fun endpoint(endpoint: String) = endpoint(JsonField.of(endpoint)) + + /** + * Sets [Builder.endpoint] to an arbitrary JSON value. + * + * You should usually call [Builder.endpoint] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun endpoint(endpoint: JsonField) = apply { this.endpoint = endpoint } + + /** Source-specific drafting guidance. */ + fun guidance(guidance: String) = guidance(JsonField.of(guidance)) + + /** + * Sets [Builder.guidance] to an arbitrary JSON value. + * + * You should usually call [Builder.guidance] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun guidance(guidance: JsonField) = apply { this.guidance = guidance } + + fun source(source: Source) = source(JsonField.of(source)) + + /** + * Sets [Builder.source] to an arbitrary JSON value. + * + * You should usually call [Builder.source] with a well-typed [Source] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun source(source: JsonField) = apply { this.source = source } + + /** Current-topic research this source supports. */ + fun useFor(useFor: String) = useFor(JsonField.of(useFor)) + + /** + * Sets [Builder.useFor] to an arbitrary JSON value. + * + * You should usually call [Builder.useFor] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun useFor(useFor: JsonField) = apply { this.useFor = useFor } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [RadarRecommendation]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .endpoint() + * .guidance() + * .source() + * .useFor() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): RadarRecommendation = + RadarRecommendation( + checkRequired("endpoint", endpoint), + checkRequired("guidance", guidance), + checkRequired("source", source), + checkRequired("useFor", useFor), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): RadarRecommendation = apply { + if (validated) { + return@apply + } + + endpoint() + guidance() + source().validate() + useFor() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (endpoint.asKnown().isPresent) 1 else 0) + + (if (guidance.asKnown().isPresent) 1 else 0) + + (source.asKnown().getOrNull()?.validity() ?: 0) + + (if (useFor.asKnown().isPresent) 1 else 0) + + class Source @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val REDDIT = of("reddit") + + @JvmField val GITHUB = of("github") + + @JvmField val TRUSTMRR = of("trustmrr") + + @JvmField val HACKER_NEWS = of("hacker_news") + + @JvmField val GOOGLE_TRENDS = of("google_trends") + + @JvmField val WIKIPEDIA = of("wikipedia") + + @JvmField val POLYMARKET = of("polymarket") + + @JvmStatic fun of(value: String) = Source(JsonField.of(value)) + } + + /** An enum containing [Source]'s known values. */ + enum class Known { + REDDIT, + GITHUB, + TRUSTMRR, + HACKER_NEWS, + GOOGLE_TRENDS, + WIKIPEDIA, + POLYMARKET, + } + + /** + * An enum containing [Source]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Source] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + REDDIT, + GITHUB, + TRUSTMRR, + HACKER_NEWS, + GOOGLE_TRENDS, + WIKIPEDIA, + POLYMARKET, + /** + * An enum member indicating that [Source] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if + * you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + REDDIT -> Value.REDDIT + GITHUB -> Value.GITHUB + TRUSTMRR -> Value.TRUSTMRR + HACKER_NEWS -> Value.HACKER_NEWS + GOOGLE_TRENDS -> Value.GOOGLE_TRENDS + WIKIPEDIA -> Value.WIKIPEDIA + POLYMARKET -> Value.POLYMARKET + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value is a + * not a known member. + */ + fun known(): Known = + when (this) { + REDDIT -> Known.REDDIT + GITHUB -> Known.GITHUB + TRUSTMRR -> Known.TRUSTMRR + HACKER_NEWS -> Known.HACKER_NEWS + GOOGLE_TRENDS -> Known.GOOGLE_TRENDS + WIKIPEDIA -> Known.WIKIPEDIA + POLYMARKET -> Known.POLYMARKET + else -> throw XTwitterScraperInvalidDataException("Unknown Source: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value does + * not have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + XTwitterScraperInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object + * doesn't match its expected type. + */ + fun validate(): Source = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Source && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is RadarRecommendation && + endpoint == other.endpoint && + guidance == other.guidance && + source == other.source && + useFor == other.useFor && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(endpoint, guidance, source, useFor, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "RadarRecommendation{endpoint=$endpoint, guidance=$guidance, source=$source, useFor=$useFor, additionalProperties=$additionalProperties}" + } + class ScorerWeight @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( @@ -1873,6 +2406,7 @@ private constructor( followUpQuestions == other.followUpQuestions && intentUrl == other.intentUrl && nextStep == other.nextStep && + radarRecommendations == other.radarRecommendations && scorerWeights == other.scorerWeights && source == other.source && topPenalties == other.topPenalties && @@ -1890,6 +2424,7 @@ private constructor( followUpQuestions, intentUrl, nextStep, + radarRecommendations, scorerWeights, source, topPenalties, @@ -1903,7 +2438,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "ComposePrepareResult{contentRules=$contentRules, engagementMultipliers=$engagementMultipliers, engagementVelocity=$engagementVelocity, followUpQuestions=$followUpQuestions, intentUrl=$intentUrl, nextStep=$nextStep, scorerWeights=$scorerWeights, source=$source, topPenalties=$topPenalties, savedStyles=$savedStyles, styleNote=$styleNote, styleTweets=$styleTweets, additionalProperties=$additionalProperties}" + "ComposePrepareResult{contentRules=$contentRules, engagementMultipliers=$engagementMultipliers, engagementVelocity=$engagementVelocity, followUpQuestions=$followUpQuestions, intentUrl=$intentUrl, nextStep=$nextStep, radarRecommendations=$radarRecommendations, scorerWeights=$scorerWeights, source=$source, topPenalties=$topPenalties, savedStyles=$savedStyles, styleNote=$styleNote, styleTweets=$styleTweets, additionalProperties=$additionalProperties}" } class ComposeRefineResult diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/radar/RadarItem.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/radar/RadarItem.kt index 588bd46..9125298 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/radar/RadarItem.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/radar/RadarItem.kt @@ -16,7 +16,6 @@ import com.x_twitter_scraper.api.core.JsonField import com.x_twitter_scraper.api.core.JsonMissing import com.x_twitter_scraper.api.core.JsonValue import com.x_twitter_scraper.api.core.checkRequired -import com.x_twitter_scraper.api.core.toImmutable import com.x_twitter_scraper.api.errors.XTwitterScraperInvalidDataException import java.time.OffsetDateTime import java.util.Collections @@ -106,6 +105,8 @@ private constructor( fun createdAt(): OffsetDateTime = createdAt.getRequired("createdAt") /** + * BCP-47 language code. und means the source did not identify a language. + * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ @@ -113,15 +114,29 @@ private constructor( /** * 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 } * - polymarket: { volume24hr: number } * - wikipedia: { views: number } * - trustmrr: { mrr, growthPercent, last30Days, total, customers, activeSubscriptions, onSale, - * xHandle?, category?, askingPrice?, country?, growthMrrPercent?, multiple?, - * paymentProvider?, rank? } + * 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. * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -173,6 +188,8 @@ private constructor( fun description(): Optional = description.getOptional("description") /** + * Source image. Startup growth items return the logo here. + * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ @@ -392,6 +409,7 @@ private constructor( */ fun createdAt(createdAt: JsonField) = apply { this.createdAt = createdAt } + /** BCP-47 language code. und means the source did not identify a language. */ fun language(language: String) = language(JsonField.of(language)) /** @@ -404,15 +422,29 @@ private constructor( /** * 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 } * - polymarket: { volume24hr: number } * - wikipedia: { views: number } * - trustmrr: { mrr, growthPercent, last30Days, total, customers, activeSubscriptions, - * onSale, xHandle?, category?, askingPrice?, country?, growthMrrPercent?, multiple?, - * paymentProvider?, rank? } + * 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. */ fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) @@ -500,6 +532,7 @@ private constructor( */ fun description(description: JsonField) = apply { this.description = description } + /** Source image. Startup growth items return the logo here. */ fun imageUrl(imageUrl: String) = imageUrl(JsonField.of(imageUrl)) /** @@ -817,26 +850,246 @@ private constructor( /** * 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 } * - polymarket: { volume24hr: number } * - wikipedia: { views: number } * - trustmrr: { mrr, growthPercent, last30Days, total, customers, activeSubscriptions, onSale, - * xHandle?, category?, askingPrice?, country?, growthMrrPercent?, multiple?, - * paymentProvider?, rank? } + * 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. */ class Metadata - @JsonCreator + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map + private val author: JsonField, + private val contentUrl: JsonField, + private val estimatedDownvotes: JsonField, + private val estimatedUpvotes: JsonField, + private val numberComments: JsonField, + private val score: JsonField, + private val selftext: JsonField, + private val sourceFormat: JsonField, + private val subreddit: JsonField, + private val upvoteRatio: JsonField, + private val additionalProperties: MutableMap, ) { + @JsonCreator + private constructor( + @JsonProperty("author") @ExcludeMissing author: JsonField = JsonMissing.of(), + @JsonProperty("contentUrl") + @ExcludeMissing + contentUrl: JsonField = JsonMissing.of(), + @JsonProperty("estimatedDownvotes") + @ExcludeMissing + estimatedDownvotes: JsonField = JsonMissing.of(), + @JsonProperty("estimatedUpvotes") + @ExcludeMissing + estimatedUpvotes: JsonField = JsonMissing.of(), + @JsonProperty("numberComments") + @ExcludeMissing + numberComments: JsonField = JsonMissing.of(), + @JsonProperty("score") @ExcludeMissing score: JsonField = JsonMissing.of(), + @JsonProperty("selftext") + @ExcludeMissing + selftext: JsonField = JsonMissing.of(), + @JsonProperty("sourceFormat") + @ExcludeMissing + sourceFormat: JsonField = JsonMissing.of(), + @JsonProperty("subreddit") + @ExcludeMissing + subreddit: JsonField = JsonMissing.of(), + @JsonProperty("upvoteRatio") + @ExcludeMissing + upvoteRatio: JsonField = JsonMissing.of(), + ) : this( + author, + contentUrl, + estimatedDownvotes, + estimatedUpvotes, + numberComments, + score, + selftext, + sourceFormat, + subreddit, + upvoteRatio, + mutableMapOf(), + ) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun author(): Optional = author.getOptional("author") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun contentUrl(): Optional = contentUrl.getOptional("contentUrl") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun estimatedDownvotes(): Optional = + estimatedDownvotes.getOptional("estimatedDownvotes") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun estimatedUpvotes(): Optional = estimatedUpvotes.getOptional("estimatedUpvotes") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun numberComments(): Optional = numberComments.getOptional("numberComments") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun score(): Optional = score.getOptional("score") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun selftext(): Optional = selftext.getOptional("selftext") + + /** + * Current items use html. json and rss are retained for legacy rows. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun sourceFormat(): Optional = sourceFormat.getOptional("sourceFormat") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun subreddit(): Optional = subreddit.getOptional("subreddit") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun upvoteRatio(): Optional = upvoteRatio.getOptional("upvoteRatio") + + /** + * Returns the raw JSON value of [author]. + * + * Unlike [author], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("author") @ExcludeMissing fun _author(): JsonField = author + + /** + * Returns the raw JSON value of [contentUrl]. + * + * Unlike [contentUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("contentUrl") + @ExcludeMissing + fun _contentUrl(): JsonField = contentUrl + + /** + * Returns the raw JSON value of [estimatedDownvotes]. + * + * Unlike [estimatedDownvotes], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("estimatedDownvotes") + @ExcludeMissing + fun _estimatedDownvotes(): JsonField = estimatedDownvotes + + /** + * Returns the raw JSON value of [estimatedUpvotes]. + * + * Unlike [estimatedUpvotes], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("estimatedUpvotes") + @ExcludeMissing + fun _estimatedUpvotes(): JsonField = estimatedUpvotes + + /** + * Returns the raw JSON value of [numberComments]. + * + * Unlike [numberComments], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("numberComments") + @ExcludeMissing + fun _numberComments(): JsonField = numberComments + + /** + * Returns the raw JSON value of [score]. + * + * Unlike [score], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("score") @ExcludeMissing fun _score(): JsonField = score + + /** + * Returns the raw JSON value of [selftext]. + * + * Unlike [selftext], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("selftext") @ExcludeMissing fun _selftext(): JsonField = selftext + + /** + * Returns the raw JSON value of [sourceFormat]. + * + * Unlike [sourceFormat], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("sourceFormat") + @ExcludeMissing + fun _sourceFormat(): JsonField = sourceFormat + + /** + * Returns the raw JSON value of [subreddit]. + * + * Unlike [subreddit], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("subreddit") @ExcludeMissing fun _subreddit(): JsonField = subreddit + + /** + * Returns the raw JSON value of [upvoteRatio]. + * + * Unlike [upvoteRatio], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("upvoteRatio") + @ExcludeMissing + fun _upvoteRatio(): JsonField = upvoteRatio + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) @@ -849,13 +1102,156 @@ private constructor( /** A builder for [Metadata]. */ class Builder internal constructor() { + private var author: JsonField = JsonMissing.of() + private var contentUrl: JsonField = JsonMissing.of() + private var estimatedDownvotes: JsonField = JsonMissing.of() + private var estimatedUpvotes: JsonField = JsonMissing.of() + private var numberComments: JsonField = JsonMissing.of() + private var score: JsonField = JsonMissing.of() + private var selftext: JsonField = JsonMissing.of() + private var sourceFormat: JsonField = JsonMissing.of() + private var subreddit: JsonField = JsonMissing.of() + private var upvoteRatio: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(metadata: Metadata) = apply { + author = metadata.author + contentUrl = metadata.contentUrl + estimatedDownvotes = metadata.estimatedDownvotes + estimatedUpvotes = metadata.estimatedUpvotes + numberComments = metadata.numberComments + score = metadata.score + selftext = metadata.selftext + sourceFormat = metadata.sourceFormat + subreddit = metadata.subreddit + upvoteRatio = metadata.upvoteRatio additionalProperties = metadata.additionalProperties.toMutableMap() } + fun author(author: String) = author(JsonField.of(author)) + + /** + * Sets [Builder.author] to an arbitrary JSON value. + * + * You should usually call [Builder.author] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun author(author: JsonField) = apply { this.author = author } + + fun contentUrl(contentUrl: String) = contentUrl(JsonField.of(contentUrl)) + + /** + * Sets [Builder.contentUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.contentUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun contentUrl(contentUrl: JsonField) = apply { this.contentUrl = contentUrl } + + fun estimatedDownvotes(estimatedDownvotes: Long) = + estimatedDownvotes(JsonField.of(estimatedDownvotes)) + + /** + * Sets [Builder.estimatedDownvotes] to an arbitrary JSON value. + * + * You should usually call [Builder.estimatedDownvotes] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun estimatedDownvotes(estimatedDownvotes: JsonField) = apply { + this.estimatedDownvotes = estimatedDownvotes + } + + fun estimatedUpvotes(estimatedUpvotes: Long) = + estimatedUpvotes(JsonField.of(estimatedUpvotes)) + + /** + * Sets [Builder.estimatedUpvotes] to an arbitrary JSON value. + * + * You should usually call [Builder.estimatedUpvotes] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun estimatedUpvotes(estimatedUpvotes: JsonField) = apply { + this.estimatedUpvotes = estimatedUpvotes + } + + fun numberComments(numberComments: Long) = numberComments(JsonField.of(numberComments)) + + /** + * Sets [Builder.numberComments] to an arbitrary JSON value. + * + * You should usually call [Builder.numberComments] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun numberComments(numberComments: JsonField) = apply { + this.numberComments = numberComments + } + + fun score(score: Long) = score(JsonField.of(score)) + + /** + * Sets [Builder.score] to an arbitrary JSON value. + * + * You should usually call [Builder.score] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun score(score: JsonField) = apply { this.score = score } + + fun selftext(selftext: String) = selftext(JsonField.of(selftext)) + + /** + * Sets [Builder.selftext] to an arbitrary JSON value. + * + * You should usually call [Builder.selftext] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun selftext(selftext: JsonField) = apply { this.selftext = selftext } + + /** Current items use html. json and rss are retained for legacy rows. */ + fun sourceFormat(sourceFormat: SourceFormat) = sourceFormat(JsonField.of(sourceFormat)) + + /** + * Sets [Builder.sourceFormat] to an arbitrary JSON value. + * + * You should usually call [Builder.sourceFormat] with a well-typed [SourceFormat] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun sourceFormat(sourceFormat: JsonField) = apply { + this.sourceFormat = sourceFormat + } + + fun subreddit(subreddit: String) = subreddit(JsonField.of(subreddit)) + + /** + * Sets [Builder.subreddit] to an arbitrary JSON value. + * + * You should usually call [Builder.subreddit] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun subreddit(subreddit: JsonField) = apply { this.subreddit = subreddit } + + fun upvoteRatio(upvoteRatio: Double) = upvoteRatio(JsonField.of(upvoteRatio)) + + /** + * Sets [Builder.upvoteRatio] to an arbitrary JSON value. + * + * You should usually call [Builder.upvoteRatio] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun upvoteRatio(upvoteRatio: JsonField) = apply { + this.upvoteRatio = upvoteRatio + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -880,7 +1276,20 @@ private constructor( * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): Metadata = Metadata(additionalProperties.toImmutable()) + fun build(): Metadata = + Metadata( + author, + contentUrl, + estimatedDownvotes, + estimatedUpvotes, + numberComments, + score, + selftext, + sourceFormat, + subreddit, + upvoteRatio, + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false @@ -899,6 +1308,16 @@ private constructor( return@apply } + author() + contentUrl() + estimatedDownvotes() + estimatedUpvotes() + numberComments() + score() + selftext() + sourceFormat().ifPresent { it.validate() } + subreddit() + upvoteRatio() validated = true } @@ -917,8 +1336,165 @@ private constructor( * Used for best match union deserialization. */ @JvmSynthetic - internal fun validity(): Int = additionalProperties.count { (_, value) -> - !value.isNull() && !value.isMissing() + internal fun validity(): Int = + (if (author.asKnown().isPresent) 1 else 0) + + (if (contentUrl.asKnown().isPresent) 1 else 0) + + (if (estimatedDownvotes.asKnown().isPresent) 1 else 0) + + (if (estimatedUpvotes.asKnown().isPresent) 1 else 0) + + (if (numberComments.asKnown().isPresent) 1 else 0) + + (if (score.asKnown().isPresent) 1 else 0) + + (if (selftext.asKnown().isPresent) 1 else 0) + + (sourceFormat.asKnown().getOrNull()?.validity() ?: 0) + + (if (subreddit.asKnown().isPresent) 1 else 0) + + (if (upvoteRatio.asKnown().isPresent) 1 else 0) + + /** Current items use html. json and rss are retained for legacy rows. */ + class SourceFormat @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val HTML = of("html") + + @JvmField val JSON = of("json") + + @JvmField val RSS = of("rss") + + @JvmStatic fun of(value: String) = SourceFormat(JsonField.of(value)) + } + + /** An enum containing [SourceFormat]'s known values. */ + enum class Known { + HTML, + JSON, + RSS, + } + + /** + * An enum containing [SourceFormat]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [SourceFormat] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + HTML, + JSON, + RSS, + /** + * An enum member indicating that [SourceFormat] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + HTML -> Value.HTML + JSON -> Value.JSON + RSS -> Value.RSS + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + HTML -> Known.HTML + JSON -> Known.JSON + RSS -> Known.RSS + else -> + throw XTwitterScraperInvalidDataException("Unknown SourceFormat: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + XTwitterScraperInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): SourceFormat = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SourceFormat && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() } override fun equals(other: Any?): Boolean { @@ -926,14 +1502,40 @@ private constructor( return true } - return other is Metadata && additionalProperties == other.additionalProperties + return other is Metadata && + author == other.author && + contentUrl == other.contentUrl && + estimatedDownvotes == other.estimatedDownvotes && + estimatedUpvotes == other.estimatedUpvotes && + numberComments == other.numberComments && + score == other.score && + selftext == other.selftext && + sourceFormat == other.sourceFormat && + subreddit == other.subreddit && + upvoteRatio == other.upvoteRatio && + additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + private val hashCode: Int by lazy { + Objects.hash( + author, + contentUrl, + estimatedDownvotes, + estimatedUpvotes, + numberComments, + score, + selftext, + sourceFormat, + subreddit, + upvoteRatio, + additionalProperties, + ) + } override fun hashCode(): Int = hashCode - override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + override fun toString() = + "Metadata{author=$author, contentUrl=$contentUrl, estimatedDownvotes=$estimatedDownvotes, estimatedUpvotes=$estimatedUpvotes, numberComments=$numberComments, score=$score, selftext=$selftext, sourceFormat=$sourceFormat, subreddit=$subreddit, upvoteRatio=$upvoteRatio, additionalProperties=$additionalProperties}" } class Source @JsonCreator private constructor(private val value: JsonField) : Enum { diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveParams.kt new file mode 100644 index 0000000..7ff1115 --- /dev/null +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveParams.kt @@ -0,0 +1,199 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.x_twitter_scraper.api.models.x.accountconnectionattempts + +import com.x_twitter_scraper.api.core.Params +import com.x_twitter_scraper.api.core.http.Headers +import com.x_twitter_scraper.api.core.http.QueryParams +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Get X account connection status */ +class AccountConnectionAttemptRetrieveParams +private constructor( + private val id: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun id(): Optional = Optional.ofNullable(id) + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): AccountConnectionAttemptRetrieveParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of + * [AccountConnectionAttemptRetrieveParams]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [AccountConnectionAttemptRetrieveParams]. */ + class Builder internal constructor() { + + private var id: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from( + accountConnectionAttemptRetrieveParams: AccountConnectionAttemptRetrieveParams + ) = apply { + id = accountConnectionAttemptRetrieveParams.id + additionalHeaders = accountConnectionAttemptRetrieveParams.additionalHeaders.toBuilder() + additionalQueryParams = + accountConnectionAttemptRetrieveParams.additionalQueryParams.toBuilder() + } + + fun id(id: String?) = apply { this.id = id } + + /** Alias for calling [Builder.id] with `id.orElse(null)`. */ + fun id(id: Optional) = id(id.getOrNull()) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [AccountConnectionAttemptRetrieveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): AccountConnectionAttemptRetrieveParams = + AccountConnectionAttemptRetrieveParams( + id, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> id ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AccountConnectionAttemptRetrieveParams && + id == other.id && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(id, additionalHeaders, additionalQueryParams) + + override fun toString() = + "AccountConnectionAttemptRetrieveParams{id=$id, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponse.kt new file mode 100644 index 0000000..f445ea9 --- /dev/null +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponse.kt @@ -0,0 +1,1932 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.x_twitter_scraper.api.models.x.accountconnectionattempts + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.x_twitter_scraper.api.core.BaseDeserializer +import com.x_twitter_scraper.api.core.BaseSerializer +import com.x_twitter_scraper.api.core.Enum +import com.x_twitter_scraper.api.core.ExcludeMissing +import com.x_twitter_scraper.api.core.JsonField +import com.x_twitter_scraper.api.core.JsonMissing +import com.x_twitter_scraper.api.core.JsonValue +import com.x_twitter_scraper.api.core.allMaxBy +import com.x_twitter_scraper.api.core.checkRequired +import com.x_twitter_scraper.api.core.getOrThrow +import com.x_twitter_scraper.api.errors.XTwitterScraperInvalidDataException +import java.time.OffsetDateTime +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** The connection is still in progress. */ +@JsonDeserialize(using = AccountConnectionAttemptRetrieveResponse.Deserializer::class) +@JsonSerialize(using = AccountConnectionAttemptRetrieveResponse.Serializer::class) +class AccountConnectionAttemptRetrieveResponse +private constructor( + private val xAccountConnectionAttemptPending: XAccountConnectionAttemptPending? = null, + private val xAccountConnectionAttemptSuccess: XAccountConnectionAttemptSuccess? = null, + private val xAccountConnectionAttemptFailed: XAccountConnectionAttemptFailed? = null, + private val xAccountConnectionChallenge: XAccountConnectionChallenge? = null, + private val _json: JsonValue? = null, +) { + + /** The connection is still in progress. */ + fun xAccountConnectionAttemptPending(): Optional = + Optional.ofNullable(xAccountConnectionAttemptPending) + + /** The account connected successfully. */ + fun xAccountConnectionAttemptSuccess(): Optional = + Optional.ofNullable(xAccountConnectionAttemptSuccess) + + /** The connection reached a final failure. */ + fun xAccountConnectionAttemptFailed(): Optional = + Optional.ofNullable(xAccountConnectionAttemptFailed) + + /** + * Resumable account connection challenge. Submit the email code to finish the same connection + * attempt. + */ + fun xAccountConnectionChallenge(): Optional = + Optional.ofNullable(xAccountConnectionChallenge) + + fun isXAccountConnectionAttemptPending(): Boolean = xAccountConnectionAttemptPending != null + + fun isXAccountConnectionAttemptSuccess(): Boolean = xAccountConnectionAttemptSuccess != null + + fun isXAccountConnectionAttemptFailed(): Boolean = xAccountConnectionAttemptFailed != null + + fun isXAccountConnectionChallenge(): Boolean = xAccountConnectionChallenge != null + + /** The connection is still in progress. */ + fun asXAccountConnectionAttemptPending(): XAccountConnectionAttemptPending = + xAccountConnectionAttemptPending.getOrThrow("xAccountConnectionAttemptPending") + + /** The account connected successfully. */ + fun asXAccountConnectionAttemptSuccess(): XAccountConnectionAttemptSuccess = + xAccountConnectionAttemptSuccess.getOrThrow("xAccountConnectionAttemptSuccess") + + /** The connection reached a final failure. */ + fun asXAccountConnectionAttemptFailed(): XAccountConnectionAttemptFailed = + xAccountConnectionAttemptFailed.getOrThrow("xAccountConnectionAttemptFailed") + + /** + * Resumable account connection challenge. Submit the email code to finish the same connection + * attempt. + */ + fun asXAccountConnectionChallenge(): XAccountConnectionChallenge = + xAccountConnectionChallenge.getOrThrow("xAccountConnectionChallenge") + + fun _json(): Optional = Optional.ofNullable(_json) + + /** + * Maps this instance's current variant to a value of type [T] using the given [visitor]. + * + * Note that this method is _not_ forwards compatible with new variants from the API, unless + * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of the + * SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.x_twitter_scraper.api.core.JsonValue; + * import java.util.Optional; + * + * Optional result = accountConnectionAttemptRetrieveResponse.accept(new AccountConnectionAttemptRetrieveResponse.Visitor>() { + * @Override + * public Optional visitXAccountConnectionAttemptPending(XAccountConnectionAttemptPending xAccountConnectionAttemptPending) { + * return Optional.of(xAccountConnectionAttemptPending.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws XTwitterScraperInvalidDataException if [Visitor.unknown] is not overridden in + * [visitor] and the current variant is unknown. + */ + fun accept(visitor: Visitor): T = + when { + xAccountConnectionAttemptPending != null -> + visitor.visitXAccountConnectionAttemptPending(xAccountConnectionAttemptPending) + xAccountConnectionAttemptSuccess != null -> + visitor.visitXAccountConnectionAttemptSuccess(xAccountConnectionAttemptSuccess) + xAccountConnectionAttemptFailed != null -> + visitor.visitXAccountConnectionAttemptFailed(xAccountConnectionAttemptFailed) + xAccountConnectionChallenge != null -> + visitor.visitXAccountConnectionChallenge(xAccountConnectionChallenge) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't match + * its expected type. + */ + fun validate(): AccountConnectionAttemptRetrieveResponse = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitXAccountConnectionAttemptPending( + xAccountConnectionAttemptPending: XAccountConnectionAttemptPending + ) { + xAccountConnectionAttemptPending.validate() + } + + override fun visitXAccountConnectionAttemptSuccess( + xAccountConnectionAttemptSuccess: XAccountConnectionAttemptSuccess + ) { + xAccountConnectionAttemptSuccess.validate() + } + + override fun visitXAccountConnectionAttemptFailed( + xAccountConnectionAttemptFailed: XAccountConnectionAttemptFailed + ) { + xAccountConnectionAttemptFailed.validate() + } + + override fun visitXAccountConnectionChallenge( + xAccountConnectionChallenge: XAccountConnectionChallenge + ) { + xAccountConnectionChallenge.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitXAccountConnectionAttemptPending( + xAccountConnectionAttemptPending: XAccountConnectionAttemptPending + ) = xAccountConnectionAttemptPending.validity() + + override fun visitXAccountConnectionAttemptSuccess( + xAccountConnectionAttemptSuccess: XAccountConnectionAttemptSuccess + ) = xAccountConnectionAttemptSuccess.validity() + + override fun visitXAccountConnectionAttemptFailed( + xAccountConnectionAttemptFailed: XAccountConnectionAttemptFailed + ) = xAccountConnectionAttemptFailed.validity() + + override fun visitXAccountConnectionChallenge( + xAccountConnectionChallenge: XAccountConnectionChallenge + ) = xAccountConnectionChallenge.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AccountConnectionAttemptRetrieveResponse && + xAccountConnectionAttemptPending == other.xAccountConnectionAttemptPending && + xAccountConnectionAttemptSuccess == other.xAccountConnectionAttemptSuccess && + xAccountConnectionAttemptFailed == other.xAccountConnectionAttemptFailed && + xAccountConnectionChallenge == other.xAccountConnectionChallenge + } + + override fun hashCode(): Int = + Objects.hash( + xAccountConnectionAttemptPending, + xAccountConnectionAttemptSuccess, + xAccountConnectionAttemptFailed, + xAccountConnectionChallenge, + ) + + override fun toString(): String = + when { + xAccountConnectionAttemptPending != null -> + "AccountConnectionAttemptRetrieveResponse{xAccountConnectionAttemptPending=$xAccountConnectionAttemptPending}" + xAccountConnectionAttemptSuccess != null -> + "AccountConnectionAttemptRetrieveResponse{xAccountConnectionAttemptSuccess=$xAccountConnectionAttemptSuccess}" + xAccountConnectionAttemptFailed != null -> + "AccountConnectionAttemptRetrieveResponse{xAccountConnectionAttemptFailed=$xAccountConnectionAttemptFailed}" + xAccountConnectionChallenge != null -> + "AccountConnectionAttemptRetrieveResponse{xAccountConnectionChallenge=$xAccountConnectionChallenge}" + _json != null -> "AccountConnectionAttemptRetrieveResponse{_unknown=$_json}" + else -> throw IllegalStateException("Invalid AccountConnectionAttemptRetrieveResponse") + } + + companion object { + + /** The connection is still in progress. */ + @JvmStatic + fun ofXAccountConnectionAttemptPending( + xAccountConnectionAttemptPending: XAccountConnectionAttemptPending + ) = + AccountConnectionAttemptRetrieveResponse( + xAccountConnectionAttemptPending = xAccountConnectionAttemptPending + ) + + /** The account connected successfully. */ + @JvmStatic + fun ofXAccountConnectionAttemptSuccess( + xAccountConnectionAttemptSuccess: XAccountConnectionAttemptSuccess + ) = + AccountConnectionAttemptRetrieveResponse( + xAccountConnectionAttemptSuccess = xAccountConnectionAttemptSuccess + ) + + /** The connection reached a final failure. */ + @JvmStatic + fun ofXAccountConnectionAttemptFailed( + xAccountConnectionAttemptFailed: XAccountConnectionAttemptFailed + ) = + AccountConnectionAttemptRetrieveResponse( + xAccountConnectionAttemptFailed = xAccountConnectionAttemptFailed + ) + + /** + * Resumable account connection challenge. Submit the email code to finish the same + * connection attempt. + */ + @JvmStatic + fun ofXAccountConnectionChallenge( + xAccountConnectionChallenge: XAccountConnectionChallenge + ) = + AccountConnectionAttemptRetrieveResponse( + xAccountConnectionChallenge = xAccountConnectionChallenge + ) + } + + /** + * An interface that defines how to map each variant of + * [AccountConnectionAttemptRetrieveResponse] to a value of type [T]. + */ + interface Visitor { + + /** The connection is still in progress. */ + fun visitXAccountConnectionAttemptPending( + xAccountConnectionAttemptPending: XAccountConnectionAttemptPending + ): T + + /** The account connected successfully. */ + fun visitXAccountConnectionAttemptSuccess( + xAccountConnectionAttemptSuccess: XAccountConnectionAttemptSuccess + ): T + + /** The connection reached a final failure. */ + fun visitXAccountConnectionAttemptFailed( + xAccountConnectionAttemptFailed: XAccountConnectionAttemptFailed + ): T + + /** + * Resumable account connection challenge. Submit the email code to finish the same + * connection attempt. + */ + fun visitXAccountConnectionChallenge( + xAccountConnectionChallenge: XAccountConnectionChallenge + ): T + + /** + * Maps an unknown variant of [AccountConnectionAttemptRetrieveResponse] to a value of type + * [T]. + * + * An instance of [AccountConnectionAttemptRetrieveResponse] can contain an unknown variant + * if it was deserialized from data that doesn't match any known variant. For example, if + * the SDK is on an older version than the API, then the API may respond with new variants + * that the SDK is unaware of. + * + * @throws XTwitterScraperInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw XTwitterScraperInvalidDataException( + "Unknown AccountConnectionAttemptRetrieveResponse: $json" + ) + } + } + + internal class Deserializer : + BaseDeserializer( + AccountConnectionAttemptRetrieveResponse::class + ) { + + override fun ObjectCodec.deserialize( + node: JsonNode + ): AccountConnectionAttemptRetrieveResponse { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { + AccountConnectionAttemptRetrieveResponse( + xAccountConnectionAttemptPending = it, + _json = json, + ) + }, + tryDeserialize(node, jacksonTypeRef()) + ?.let { + AccountConnectionAttemptRetrieveResponse( + xAccountConnectionAttemptSuccess = it, + _json = json, + ) + }, + tryDeserialize(node, jacksonTypeRef()) + ?.let { + AccountConnectionAttemptRetrieveResponse( + xAccountConnectionAttemptFailed = it, + _json = json, + ) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + AccountConnectionAttemptRetrieveResponse( + xAccountConnectionChallenge = it, + _json = json, + ) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with all + // the possible variants (e.g. deserializing from boolean). + 0 -> AccountConnectionAttemptRetrieveResponse(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : + BaseSerializer( + AccountConnectionAttemptRetrieveResponse::class + ) { + + override fun serialize( + value: AccountConnectionAttemptRetrieveResponse, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.xAccountConnectionAttemptPending != null -> + generator.writeObject(value.xAccountConnectionAttemptPending) + value.xAccountConnectionAttemptSuccess != null -> + generator.writeObject(value.xAccountConnectionAttemptSuccess) + value.xAccountConnectionAttemptFailed != null -> + generator.writeObject(value.xAccountConnectionAttemptFailed) + value.xAccountConnectionChallenge != null -> + generator.writeObject(value.xAccountConnectionChallenge) + value._json != null -> generator.writeObject(value._json) + else -> + throw IllegalStateException("Invalid AccountConnectionAttemptRetrieveResponse") + } + } + } + + /** The connection is still in progress. */ + class XAccountConnectionAttemptPending + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val object_: JsonValue, + private val pollAfterMs: JsonField, + private val status: JsonValue, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("object") @ExcludeMissing object_: JsonValue = JsonMissing.of(), + @JsonProperty("pollAfterMs") + @ExcludeMissing + pollAfterMs: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonValue = JsonMissing.of(), + ) : this(id, object_, pollAfterMs, status, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun id(): String = id.getRequired("id") + + /** + * Expected to always return the following: + * ```java + * JsonValue.from("x_account_connection_attempt") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("object") @ExcludeMissing fun _object_(): JsonValue = object_ + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun pollAfterMs(): Long = pollAfterMs.getRequired("pollAfterMs") + + /** + * Expected to always return the following: + * ```java + * JsonValue.from("pending") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonValue = status + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [pollAfterMs]. + * + * Unlike [pollAfterMs], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("pollAfterMs") + @ExcludeMissing + fun _pollAfterMs(): JsonField = pollAfterMs + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [XAccountConnectionAttemptPending]. + * + * The following fields are required: + * ```java + * .id() + * .pollAfterMs() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [XAccountConnectionAttemptPending]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var object_: JsonValue = JsonValue.from("x_account_connection_attempt") + private var pollAfterMs: JsonField? = null + private var status: JsonValue = JsonValue.from("pending") + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(xAccountConnectionAttemptPending: XAccountConnectionAttemptPending) = + apply { + id = xAccountConnectionAttemptPending.id + object_ = xAccountConnectionAttemptPending.object_ + pollAfterMs = xAccountConnectionAttemptPending.pollAfterMs + status = xAccountConnectionAttemptPending.status + additionalProperties = + xAccountConnectionAttemptPending.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("x_account_connection_attempt") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun object_(object_: JsonValue) = apply { this.object_ = object_ } + + fun pollAfterMs(pollAfterMs: Long) = pollAfterMs(JsonField.of(pollAfterMs)) + + /** + * Sets [Builder.pollAfterMs] to an arbitrary JSON value. + * + * You should usually call [Builder.pollAfterMs] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun pollAfterMs(pollAfterMs: JsonField) = apply { this.pollAfterMs = pollAfterMs } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("pending") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun status(status: JsonValue) = apply { this.status = status } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [XAccountConnectionAttemptPending]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .id() + * .pollAfterMs() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): XAccountConnectionAttemptPending = + XAccountConnectionAttemptPending( + checkRequired("id", id), + object_, + checkRequired("pollAfterMs", pollAfterMs), + status, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): XAccountConnectionAttemptPending = apply { + if (validated) { + return@apply + } + + id() + _object_().let { + if (it != JsonValue.from("x_account_connection_attempt")) { + throw XTwitterScraperInvalidDataException("'object_' is invalid, received $it") + } + } + pollAfterMs() + _status().let { + if (it != JsonValue.from("pending")) { + throw XTwitterScraperInvalidDataException("'status' is invalid, received $it") + } + } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + object_.let { if (it == JsonValue.from("x_account_connection_attempt")) 1 else 0 } + + (if (pollAfterMs.asKnown().isPresent) 1 else 0) + + status.let { if (it == JsonValue.from("pending")) 1 else 0 } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XAccountConnectionAttemptPending && + id == other.id && + object_ == other.object_ && + pollAfterMs == other.pollAfterMs && + status == other.status && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, object_, pollAfterMs, status, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "XAccountConnectionAttemptPending{id=$id, object_=$object_, pollAfterMs=$pollAfterMs, status=$status, additionalProperties=$additionalProperties}" + } + + /** The account connected successfully. */ + class XAccountConnectionAttemptSuccess + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val object_: JsonValue, + private val status: JsonValue, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("object") @ExcludeMissing object_: JsonValue = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonValue = JsonMissing.of(), + ) : this(id, object_, status, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun id(): String = id.getRequired("id") + + /** + * Expected to always return the following: + * ```java + * JsonValue.from("x_account_connection_attempt") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("object") @ExcludeMissing fun _object_(): JsonValue = object_ + + /** + * Expected to always return the following: + * ```java + * JsonValue.from("success") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonValue = status + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [XAccountConnectionAttemptSuccess]. + * + * The following fields are required: + * ```java + * .id() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [XAccountConnectionAttemptSuccess]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var object_: JsonValue = JsonValue.from("x_account_connection_attempt") + private var status: JsonValue = JsonValue.from("success") + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(xAccountConnectionAttemptSuccess: XAccountConnectionAttemptSuccess) = + apply { + id = xAccountConnectionAttemptSuccess.id + object_ = xAccountConnectionAttemptSuccess.object_ + status = xAccountConnectionAttemptSuccess.status + additionalProperties = + xAccountConnectionAttemptSuccess.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("x_account_connection_attempt") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun object_(object_: JsonValue) = apply { this.object_ = object_ } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("success") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun status(status: JsonValue) = apply { this.status = status } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [XAccountConnectionAttemptSuccess]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .id() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): XAccountConnectionAttemptSuccess = + XAccountConnectionAttemptSuccess( + checkRequired("id", id), + object_, + status, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): XAccountConnectionAttemptSuccess = apply { + if (validated) { + return@apply + } + + id() + _object_().let { + if (it != JsonValue.from("x_account_connection_attempt")) { + throw XTwitterScraperInvalidDataException("'object_' is invalid, received $it") + } + } + _status().let { + if (it != JsonValue.from("success")) { + throw XTwitterScraperInvalidDataException("'status' is invalid, received $it") + } + } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + object_.let { if (it == JsonValue.from("x_account_connection_attempt")) 1 else 0 } + + status.let { if (it == JsonValue.from("success")) 1 else 0 } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XAccountConnectionAttemptSuccess && + id == other.id && + object_ == other.object_ && + status == other.status && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, object_, status, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "XAccountConnectionAttemptSuccess{id=$id, object_=$object_, status=$status, additionalProperties=$additionalProperties}" + } + + /** The connection reached a final failure. */ + class XAccountConnectionAttemptFailed + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val error: JsonField, + private val object_: JsonValue, + private val retryable: JsonField, + private val status: JsonValue, + private val reason: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("error") @ExcludeMissing error: JsonField = JsonMissing.of(), + @JsonProperty("object") @ExcludeMissing object_: JsonValue = JsonMissing.of(), + @JsonProperty("retryable") + @ExcludeMissing + retryable: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonValue = JsonMissing.of(), + @JsonProperty("reason") @ExcludeMissing reason: JsonField = JsonMissing.of(), + ) : this(id, error, object_, retryable, status, reason, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun id(): String = id.getRequired("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun error(): String = error.getRequired("error") + + /** + * Expected to always return the following: + * ```java + * JsonValue.from("x_account_connection_attempt") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("object") @ExcludeMissing fun _object_(): JsonValue = object_ + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun retryable(): Boolean = retryable.getRequired("retryable") + + /** + * Expected to always return the following: + * ```java + * JsonValue.from("failed") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonValue = status + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun reason(): Optional = reason.getOptional("reason") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [error]. + * + * Unlike [error], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("error") @ExcludeMissing fun _error(): JsonField = error + + /** + * Returns the raw JSON value of [retryable]. + * + * Unlike [retryable], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("retryable") @ExcludeMissing fun _retryable(): JsonField = retryable + + /** + * Returns the raw JSON value of [reason]. + * + * Unlike [reason], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("reason") @ExcludeMissing fun _reason(): JsonField = reason + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [XAccountConnectionAttemptFailed]. + * + * The following fields are required: + * ```java + * .id() + * .error() + * .retryable() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [XAccountConnectionAttemptFailed]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var error: JsonField? = null + private var object_: JsonValue = JsonValue.from("x_account_connection_attempt") + private var retryable: JsonField? = null + private var status: JsonValue = JsonValue.from("failed") + private var reason: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(xAccountConnectionAttemptFailed: XAccountConnectionAttemptFailed) = + apply { + id = xAccountConnectionAttemptFailed.id + error = xAccountConnectionAttemptFailed.error + object_ = xAccountConnectionAttemptFailed.object_ + retryable = xAccountConnectionAttemptFailed.retryable + status = xAccountConnectionAttemptFailed.status + reason = xAccountConnectionAttemptFailed.reason + additionalProperties = + xAccountConnectionAttemptFailed.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun error(error: String) = error(JsonField.of(error)) + + /** + * Sets [Builder.error] to an arbitrary JSON value. + * + * You should usually call [Builder.error] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun error(error: JsonField) = apply { this.error = error } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("x_account_connection_attempt") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun object_(object_: JsonValue) = apply { this.object_ = object_ } + + fun retryable(retryable: Boolean) = retryable(JsonField.of(retryable)) + + /** + * Sets [Builder.retryable] to an arbitrary JSON value. + * + * You should usually call [Builder.retryable] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun retryable(retryable: JsonField) = apply { this.retryable = retryable } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("failed") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun status(status: JsonValue) = apply { this.status = status } + + fun reason(reason: String) = reason(JsonField.of(reason)) + + /** + * Sets [Builder.reason] to an arbitrary JSON value. + * + * You should usually call [Builder.reason] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun reason(reason: JsonField) = apply { this.reason = reason } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [XAccountConnectionAttemptFailed]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .id() + * .error() + * .retryable() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): XAccountConnectionAttemptFailed = + XAccountConnectionAttemptFailed( + checkRequired("id", id), + checkRequired("error", error), + object_, + checkRequired("retryable", retryable), + status, + reason, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): XAccountConnectionAttemptFailed = apply { + if (validated) { + return@apply + } + + id() + error() + _object_().let { + if (it != JsonValue.from("x_account_connection_attempt")) { + throw XTwitterScraperInvalidDataException("'object_' is invalid, received $it") + } + } + retryable() + _status().let { + if (it != JsonValue.from("failed")) { + throw XTwitterScraperInvalidDataException("'status' is invalid, received $it") + } + } + reason() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (error.asKnown().isPresent) 1 else 0) + + object_.let { if (it == JsonValue.from("x_account_connection_attempt")) 1 else 0 } + + (if (retryable.asKnown().isPresent) 1 else 0) + + status.let { if (it == JsonValue.from("failed")) 1 else 0 } + + (if (reason.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XAccountConnectionAttemptFailed && + id == other.id && + error == other.error && + object_ == other.object_ && + retryable == other.retryable && + status == other.status && + reason == other.reason && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, error, object_, retryable, status, reason, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "XAccountConnectionAttemptFailed{id=$id, error=$error, object_=$object_, retryable=$retryable, status=$status, reason=$reason, additionalProperties=$additionalProperties}" + } + + /** + * Resumable account connection challenge. Submit the email code to finish the same connection + * attempt. + */ + class XAccountConnectionChallenge + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val expiresAt: JsonField, + private val message: JsonField, + private val object_: JsonField, + private val status: JsonField, + private val username: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("expiresAt") + @ExcludeMissing + expiresAt: JsonField = JsonMissing.of(), + @JsonProperty("message") @ExcludeMissing message: JsonField = JsonMissing.of(), + @JsonProperty("object") @ExcludeMissing object_: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("username") + @ExcludeMissing + username: JsonField = JsonMissing.of(), + ) : this(id, expiresAt, message, object_, status, username, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun id(): String = id.getRequired("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun expiresAt(): OffsetDateTime = expiresAt.getRequired("expiresAt") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun message(): String = message.getRequired("message") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun object_(): Object = object_.getRequired("object") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun status(): Status = status.getRequired("status") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun username(): String = username.getRequired("username") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [expiresAt]. + * + * Unlike [expiresAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("expiresAt") + @ExcludeMissing + fun _expiresAt(): JsonField = expiresAt + + /** + * Returns the raw JSON value of [message]. + * + * Unlike [message], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message + + /** + * Returns the raw JSON value of [object_]. + * + * Unlike [object_], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("object") @ExcludeMissing fun _object_(): JsonField = object_ + + /** + * Returns the raw JSON value of [status]. + * + * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + + /** + * Returns the raw JSON value of [username]. + * + * Unlike [username], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("username") @ExcludeMissing fun _username(): JsonField = username + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [XAccountConnectionChallenge]. + * + * The following fields are required: + * ```java + * .id() + * .expiresAt() + * .message() + * .object_() + * .status() + * .username() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [XAccountConnectionChallenge]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var expiresAt: JsonField? = null + private var message: JsonField? = null + private var object_: JsonField? = null + private var status: JsonField? = null + private var username: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(xAccountConnectionChallenge: XAccountConnectionChallenge) = apply { + id = xAccountConnectionChallenge.id + expiresAt = xAccountConnectionChallenge.expiresAt + message = xAccountConnectionChallenge.message + object_ = xAccountConnectionChallenge.object_ + status = xAccountConnectionChallenge.status + username = xAccountConnectionChallenge.username + additionalProperties = + xAccountConnectionChallenge.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun expiresAt(expiresAt: OffsetDateTime) = expiresAt(JsonField.of(expiresAt)) + + /** + * Sets [Builder.expiresAt] to an arbitrary JSON value. + * + * You should usually call [Builder.expiresAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun expiresAt(expiresAt: JsonField) = apply { + this.expiresAt = expiresAt + } + + fun message(message: String) = message(JsonField.of(message)) + + /** + * Sets [Builder.message] to an arbitrary JSON value. + * + * You should usually call [Builder.message] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun message(message: JsonField) = apply { this.message = message } + + fun object_(object_: Object) = object_(JsonField.of(object_)) + + /** + * Sets [Builder.object_] to an arbitrary JSON value. + * + * You should usually call [Builder.object_] with a well-typed [Object] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun object_(object_: JsonField) = apply { this.object_ = object_ } + + fun status(status: Status) = status(JsonField.of(status)) + + /** + * Sets [Builder.status] to an arbitrary JSON value. + * + * You should usually call [Builder.status] with a well-typed [Status] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun status(status: JsonField) = apply { this.status = status } + + fun username(username: String) = username(JsonField.of(username)) + + /** + * Sets [Builder.username] to an arbitrary JSON value. + * + * You should usually call [Builder.username] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun username(username: JsonField) = apply { this.username = username } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [XAccountConnectionChallenge]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .id() + * .expiresAt() + * .message() + * .object_() + * .status() + * .username() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): XAccountConnectionChallenge = + XAccountConnectionChallenge( + checkRequired("id", id), + checkRequired("expiresAt", expiresAt), + checkRequired("message", message), + checkRequired("object_", object_), + checkRequired("status", status), + checkRequired("username", username), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): XAccountConnectionChallenge = apply { + if (validated) { + return@apply + } + + id() + expiresAt() + message() + object_().validate() + status().validate() + username() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (expiresAt.asKnown().isPresent) 1 else 0) + + (if (message.asKnown().isPresent) 1 else 0) + + (object_.asKnown().getOrNull()?.validity() ?: 0) + + (status.asKnown().getOrNull()?.validity() ?: 0) + + (if (username.asKnown().isPresent) 1 else 0) + + class Object @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val X_ACCOUNT_CONNECTION_CHALLENGE = of("x_account_connection_challenge") + + @JvmStatic fun of(value: String) = Object(JsonField.of(value)) + } + + /** An enum containing [Object]'s known values. */ + enum class Known { + X_ACCOUNT_CONNECTION_CHALLENGE + } + + /** + * An enum containing [Object]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Object] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + X_ACCOUNT_CONNECTION_CHALLENGE, + /** + * An enum member indicating that [Object] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + X_ACCOUNT_CONNECTION_CHALLENGE -> Value.X_ACCOUNT_CONNECTION_CHALLENGE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + X_ACCOUNT_CONNECTION_CHALLENGE -> Known.X_ACCOUNT_CONNECTION_CHALLENGE + else -> throw XTwitterScraperInvalidDataException("Unknown Object: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + XTwitterScraperInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Object = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Object && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class Status @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val REQUIRES_EMAIL_CODE = of("requires_email_code") + + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) + } + + /** An enum containing [Status]'s known values. */ + enum class Known { + REQUIRES_EMAIL_CODE + } + + /** + * An enum containing [Status]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Status] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + REQUIRES_EMAIL_CODE, + /** + * An enum member indicating that [Status] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + REQUIRES_EMAIL_CODE -> Value.REQUIRES_EMAIL_CODE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + REQUIRES_EMAIL_CODE -> Known.REQUIRES_EMAIL_CODE + else -> throw XTwitterScraperInvalidDataException("Unknown Status: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + XTwitterScraperInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Status = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Status && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XAccountConnectionChallenge && + id == other.id && + expiresAt == other.expiresAt && + message == other.message && + object_ == other.object_ && + status == other.status && + username == other.username && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, expiresAt, message, object_, status, username, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "XAccountConnectionChallenge{id=$id, expiresAt=$expiresAt, message=$message, object_=$object_, status=$status, username=$username, additionalProperties=$additionalProperties}" + } +} diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateParams.kt index e68417d..4d7b2be 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateParams.kt @@ -21,7 +21,6 @@ import com.x_twitter_scraper.api.core.http.QueryParams import com.x_twitter_scraper.api.errors.XTwitterScraperInvalidDataException import java.util.Collections import java.util.Objects -import java.util.Optional /** Connect X account */ class AccountCreateParams @@ -48,20 +47,20 @@ private constructor( fun password(): String = body.password() /** - * X username + * Authenticator App TOTP secret required for durable login * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun username(): String = body.username() + fun totpSecret(): String = body.totpSecret() /** - * TOTP secret for 2FA + * X username * - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun totpSecret(): Optional = body.totpSecret() + fun username(): String = body.username() /** * Returns the raw JSON value of [email]. @@ -78,18 +77,18 @@ private constructor( fun _password(): JsonField = body._password() /** - * Returns the raw JSON value of [username]. + * Returns the raw JSON value of [totpSecret]. * - * Unlike [username], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [totpSecret], this method doesn't throw if the JSON field has an unexpected type. */ - fun _username(): JsonField = body._username() + fun _totpSecret(): JsonField = body._totpSecret() /** - * Returns the raw JSON value of [totpSecret]. + * Returns the raw JSON value of [username]. * - * Unlike [totpSecret], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [username], this method doesn't throw if the JSON field has an unexpected type. */ - fun _totpSecret(): JsonField = body._totpSecret() + fun _username(): JsonField = body._username() fun _additionalBodyProperties(): Map = body._additionalProperties() @@ -110,6 +109,7 @@ private constructor( * ```java * .email() * .password() + * .totpSecret() * .username() * ``` */ @@ -137,8 +137,8 @@ private constructor( * Otherwise, it's more convenient to use the top-level setters instead: * - [email] * - [password] - * - [username] * - [totpSecret] + * - [username] */ fun body(body: Body) = apply { this.body = body.toBuilder() } @@ -164,18 +164,7 @@ private constructor( */ fun password(password: JsonField) = apply { body.password(password) } - /** X username */ - fun username(username: String) = apply { body.username(username) } - - /** - * Sets [Builder.username] to an arbitrary JSON value. - * - * You should usually call [Builder.username] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun username(username: JsonField) = apply { body.username(username) } - - /** TOTP secret for 2FA */ + /** Authenticator App TOTP secret required for durable login */ fun totpSecret(totpSecret: String) = apply { body.totpSecret(totpSecret) } /** @@ -187,6 +176,17 @@ private constructor( */ fun totpSecret(totpSecret: JsonField) = apply { body.totpSecret(totpSecret) } + /** X username */ + fun username(username: String) = apply { body.username(username) } + + /** + * Sets [Builder.username] to an arbitrary JSON value. + * + * You should usually call [Builder.username] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun username(username: JsonField) = apply { body.username(username) } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { body.additionalProperties(additionalBodyProperties) } @@ -313,6 +313,7 @@ private constructor( * ```java * .email() * .password() + * .totpSecret() * .username() * ``` * @@ -337,8 +338,8 @@ private constructor( private constructor( private val email: JsonField, private val password: JsonField, - private val username: JsonField, private val totpSecret: JsonField, + private val username: JsonField, private val additionalProperties: MutableMap, ) { @@ -348,13 +349,13 @@ private constructor( @JsonProperty("password") @ExcludeMissing password: JsonField = JsonMissing.of(), - @JsonProperty("username") - @ExcludeMissing - username: JsonField = JsonMissing.of(), @JsonProperty("totp_secret") @ExcludeMissing totpSecret: JsonField = JsonMissing.of(), - ) : this(email, password, username, totpSecret, mutableMapOf()) + @JsonProperty("username") + @ExcludeMissing + username: JsonField = JsonMissing.of(), + ) : this(email, password, totpSecret, username, mutableMapOf()) /** * Account email @@ -375,21 +376,22 @@ private constructor( fun password(): String = password.getRequired("password") /** - * X username + * Authenticator App TOTP secret required for durable login * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or * is unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun username(): String = username.getRequired("username") + fun totpSecret(): String = totpSecret.getRequired("totp_secret") /** - * TOTP secret for 2FA + * X username * - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun totpSecret(): Optional = totpSecret.getOptional("totp_secret") + fun username(): String = username.getRequired("username") /** * Returns the raw JSON value of [email]. @@ -405,13 +407,6 @@ private constructor( */ @JsonProperty("password") @ExcludeMissing fun _password(): JsonField = password - /** - * Returns the raw JSON value of [username]. - * - * Unlike [username], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("username") @ExcludeMissing fun _username(): JsonField = username - /** * Returns the raw JSON value of [totpSecret]. * @@ -421,6 +416,13 @@ private constructor( @ExcludeMissing fun _totpSecret(): JsonField = totpSecret + /** + * Returns the raw JSON value of [username]. + * + * Unlike [username], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("username") @ExcludeMissing fun _username(): JsonField = username + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -442,6 +444,7 @@ private constructor( * ```java * .email() * .password() + * .totpSecret() * .username() * ``` */ @@ -453,16 +456,16 @@ private constructor( private var email: JsonField? = null private var password: JsonField? = null + private var totpSecret: JsonField? = null private var username: JsonField? = null - private var totpSecret: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(body: Body) = apply { email = body.email password = body.password - username = body.username totpSecret = body.totpSecret + username = body.username additionalProperties = body.additionalProperties.toMutableMap() } @@ -490,29 +493,29 @@ private constructor( */ fun password(password: JsonField) = apply { this.password = password } - /** X username */ - fun username(username: String) = username(JsonField.of(username)) + /** Authenticator App TOTP secret required for durable login */ + fun totpSecret(totpSecret: String) = totpSecret(JsonField.of(totpSecret)) /** - * Sets [Builder.username] to an arbitrary JSON value. + * Sets [Builder.totpSecret] to an arbitrary JSON value. * - * You should usually call [Builder.username] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet + * You should usually call [Builder.totpSecret] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun username(username: JsonField) = apply { this.username = username } + fun totpSecret(totpSecret: JsonField) = apply { this.totpSecret = totpSecret } - /** TOTP secret for 2FA */ - fun totpSecret(totpSecret: String) = totpSecret(JsonField.of(totpSecret)) + /** X username */ + fun username(username: String) = username(JsonField.of(username)) /** - * Sets [Builder.totpSecret] to an arbitrary JSON value. + * Sets [Builder.username] to an arbitrary JSON value. * - * You should usually call [Builder.totpSecret] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not yet + * You should usually call [Builder.username] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun totpSecret(totpSecret: JsonField) = apply { this.totpSecret = totpSecret } + fun username(username: JsonField) = apply { this.username = username } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -542,6 +545,7 @@ private constructor( * ```java * .email() * .password() + * .totpSecret() * .username() * ``` * @@ -551,8 +555,8 @@ private constructor( Body( checkRequired("email", email), checkRequired("password", password), + checkRequired("totpSecret", totpSecret), checkRequired("username", username), - totpSecret, additionalProperties.toMutableMap(), ) } @@ -575,8 +579,8 @@ private constructor( email() password() - username() totpSecret() + username() validated = true } @@ -598,8 +602,8 @@ private constructor( internal fun validity(): Int = (if (email.asKnown().isPresent) 1 else 0) + (if (password.asKnown().isPresent) 1 else 0) + - (if (username.asKnown().isPresent) 1 else 0) + - (if (totpSecret.asKnown().isPresent) 1 else 0) + (if (totpSecret.asKnown().isPresent) 1 else 0) + + (if (username.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -609,19 +613,19 @@ private constructor( return other is Body && email == other.email && password == other.password && - username == other.username && totpSecret == other.totpSecret && + username == other.username && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(email, password, username, totpSecret, additionalProperties) + Objects.hash(email, password, totpSecret, username, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Body{email=$email, password=$password, username=$username, totpSecret=$totpSecret, additionalProperties=$additionalProperties}" + "Body{email=$email, password=$password, totpSecret=$totpSecret, username=$username, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponse.kt index 7647166..cf0b97b 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponse.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponse.kt @@ -9,123 +9,17 @@ package com.x_twitter_scraper.api.models.x.accounts import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import com.x_twitter_scraper.api.core.Enum import com.x_twitter_scraper.api.core.ExcludeMissing -import com.x_twitter_scraper.api.core.JsonField -import com.x_twitter_scraper.api.core.JsonMissing import com.x_twitter_scraper.api.core.JsonValue -import com.x_twitter_scraper.api.core.checkRequired import com.x_twitter_scraper.api.errors.XTwitterScraperInvalidDataException -import java.time.OffsetDateTime import java.util.Collections import java.util.Objects -import kotlin.jvm.optionals.getOrNull -/** Sanitized X account summary returned by connect and reauth. */ class AccountCreateResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor( - private val id: JsonField, - private val createdAt: JsonField, - private val health: JsonField, - private val status: JsonField, - private val xUserId: JsonField, - private val xUsername: JsonField, - private val additionalProperties: MutableMap, -) { +private constructor(private val additionalProperties: MutableMap) { - @JsonCreator - private constructor( - @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), - @JsonProperty("createdAt") - @ExcludeMissing - createdAt: JsonField = JsonMissing.of(), - @JsonProperty("health") @ExcludeMissing health: JsonField = JsonMissing.of(), - @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), - @JsonProperty("xUserId") @ExcludeMissing xUserId: JsonField = JsonMissing.of(), - @JsonProperty("xUsername") @ExcludeMissing xUsername: JsonField = JsonMissing.of(), - ) : this(id, createdAt, health, status, xUserId, xUsername, mutableMapOf()) - - /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun id(): String = id.getRequired("id") - - /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun createdAt(): OffsetDateTime = createdAt.getRequired("createdAt") - - /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun health(): Health = health.getRequired("health") - - /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun status(): String = status.getRequired("status") - - /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun xUserId(): String = xUserId.getRequired("xUserId") - - /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun xUsername(): String = xUsername.getRequired("xUsername") - - /** - * Returns the raw JSON value of [id]. - * - * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id - - /** - * Returns the raw JSON value of [createdAt]. - * - * Unlike [createdAt], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("createdAt") - @ExcludeMissing - fun _createdAt(): JsonField = createdAt - - /** - * Returns the raw JSON value of [health]. - * - * Unlike [health], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("health") @ExcludeMissing fun _health(): JsonField = health - - /** - * Returns the raw JSON value of [status]. - * - * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status - - /** - * Returns the raw JSON value of [xUserId]. - * - * Unlike [xUserId], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("xUserId") @ExcludeMissing fun _xUserId(): JsonField = xUserId - - /** - * Returns the raw JSON value of [xUsername]. - * - * Unlike [xUsername], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("xUsername") @ExcludeMissing fun _xUsername(): JsonField = xUsername + @JsonCreator private constructor() : this(mutableMapOf()) @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -141,106 +35,20 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [AccountCreateResponse]. - * - * The following fields are required: - * ```java - * .id() - * .createdAt() - * .health() - * .status() - * .xUserId() - * .xUsername() - * ``` - */ + /** Returns a mutable builder for constructing an instance of [AccountCreateResponse]. */ @JvmStatic fun builder() = Builder() } /** A builder for [AccountCreateResponse]. */ class Builder internal constructor() { - private var id: JsonField? = null - private var createdAt: JsonField? = null - private var health: JsonField? = null - private var status: JsonField? = null - private var xUserId: JsonField? = null - private var xUsername: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(accountCreateResponse: AccountCreateResponse) = apply { - id = accountCreateResponse.id - createdAt = accountCreateResponse.createdAt - health = accountCreateResponse.health - status = accountCreateResponse.status - xUserId = accountCreateResponse.xUserId - xUsername = accountCreateResponse.xUsername additionalProperties = accountCreateResponse.additionalProperties.toMutableMap() } - fun id(id: String) = id(JsonField.of(id)) - - /** - * Sets [Builder.id] to an arbitrary JSON value. - * - * You should usually call [Builder.id] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun id(id: JsonField) = apply { this.id = id } - - fun createdAt(createdAt: OffsetDateTime) = createdAt(JsonField.of(createdAt)) - - /** - * Sets [Builder.createdAt] to an arbitrary JSON value. - * - * You should usually call [Builder.createdAt] with a well-typed [OffsetDateTime] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun createdAt(createdAt: JsonField) = apply { this.createdAt = createdAt } - - fun health(health: Health) = health(JsonField.of(health)) - - /** - * Sets [Builder.health] to an arbitrary JSON value. - * - * You should usually call [Builder.health] with a well-typed [Health] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun health(health: JsonField) = apply { this.health = health } - - fun status(status: String) = status(JsonField.of(status)) - - /** - * Sets [Builder.status] to an arbitrary JSON value. - * - * You should usually call [Builder.status] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun status(status: JsonField) = apply { this.status = status } - - fun xUserId(xUserId: String) = xUserId(JsonField.of(xUserId)) - - /** - * Sets [Builder.xUserId] to an arbitrary JSON value. - * - * You should usually call [Builder.xUserId] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun xUserId(xUserId: JsonField) = apply { this.xUserId = xUserId } - - fun xUsername(xUsername: String) = xUsername(JsonField.of(xUsername)) - - /** - * Sets [Builder.xUsername] to an arbitrary JSON value. - * - * You should usually call [Builder.xUsername] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun xUsername(xUsername: JsonField) = apply { this.xUsername = xUsername } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -264,29 +72,9 @@ private constructor( * Returns an immutable instance of [AccountCreateResponse]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .id() - * .createdAt() - * .health() - * .status() - * .xUserId() - * .xUsername() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): AccountCreateResponse = - AccountCreateResponse( - checkRequired("id", id), - checkRequired("createdAt", createdAt), - checkRequired("health", health), - checkRequired("status", status), - checkRequired("xUserId", xUserId), - checkRequired("xUsername", xUsername), - additionalProperties.toMutableMap(), - ) + AccountCreateResponse(additionalProperties.toMutableMap()) } private var validated: Boolean = false @@ -304,12 +92,6 @@ private constructor( return@apply } - id() - createdAt() - health().validate() - status() - xUserId() - xUsername() validated = true } @@ -326,196 +108,19 @@ private constructor( * * Used for best match union deserialization. */ - @JvmSynthetic - internal fun validity(): Int = - (if (id.asKnown().isPresent) 1 else 0) + - (if (createdAt.asKnown().isPresent) 1 else 0) + - (health.asKnown().getOrNull()?.validity() ?: 0) + - (if (status.asKnown().isPresent) 1 else 0) + - (if (xUserId.asKnown().isPresent) 1 else 0) + - (if (xUsername.asKnown().isPresent) 1 else 0) - - class Health @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val HEALTHY = of("healthy") - - @JvmField val LOCKED = of("locked") - - @JvmField val NEEDS_REAUTH = of("needsReauth") - - @JvmField val RECOVERING = of("recovering") - - @JvmField val SUSPENDED = of("suspended") - - @JvmField val TEMPORARY_ISSUE = of("temporaryIssue") - - @JvmStatic fun of(value: String) = Health(JsonField.of(value)) - } - - /** An enum containing [Health]'s known values. */ - enum class Known { - HEALTHY, - LOCKED, - NEEDS_REAUTH, - RECOVERING, - SUSPENDED, - TEMPORARY_ISSUE, - } - - /** - * An enum containing [Health]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Health] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - HEALTHY, - LOCKED, - NEEDS_REAUTH, - RECOVERING, - SUSPENDED, - TEMPORARY_ISSUE, - /** An enum member indicating that [Health] was instantiated with an unknown value. */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - HEALTHY -> Value.HEALTHY - LOCKED -> Value.LOCKED - NEEDS_REAUTH -> Value.NEEDS_REAUTH - RECOVERING -> Value.RECOVERING - SUSPENDED -> Value.SUSPENDED - TEMPORARY_ISSUE -> Value.TEMPORARY_ISSUE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws XTwitterScraperInvalidDataException if this class instance's value is a not a - * known member. - */ - fun known(): Known = - when (this) { - HEALTHY -> Known.HEALTHY - LOCKED -> Known.LOCKED - NEEDS_REAUTH -> Known.NEEDS_REAUTH - RECOVERING -> Known.RECOVERING - SUSPENDED -> Known.SUSPENDED - TEMPORARY_ISSUE -> Known.TEMPORARY_ISSUE - else -> throw XTwitterScraperInvalidDataException("Unknown Health: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws XTwitterScraperInvalidDataException if this class instance's value does not have - * the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - XTwitterScraperInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - /** - * Validates that the types of all values in this object match their expected types - * recursively. - * - * This method is _not_ forwards compatible with new types from the API for existing fields. - * - * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't - * match its expected type. - */ - fun validate(): Health = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: XTwitterScraperInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Health && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } + @JvmSynthetic internal fun validity(): Int = 0 override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is AccountCreateResponse && - id == other.id && - createdAt == other.createdAt && - health == other.health && - status == other.status && - xUserId == other.xUserId && - xUsername == other.xUsername && - additionalProperties == other.additionalProperties + return other is AccountCreateResponse && additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { - Objects.hash(id, createdAt, health, status, xUserId, xUsername, additionalProperties) - } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } override fun hashCode(): Int = hashCode - override fun toString() = - "AccountCreateResponse{id=$id, createdAt=$createdAt, health=$health, status=$status, xUserId=$xUserId, xUsername=$xUsername, additionalProperties=$additionalProperties}" + override fun toString() = "AccountCreateResponse{additionalProperties=$additionalProperties}" } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountReauthParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountReauthParams.kt index 1812e99..75f005f 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountReauthParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountReauthParams.kt @@ -52,7 +52,7 @@ private constructor( fun email(): Optional = body.email() /** - * TOTP secret for 2FA re-authentication + * Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret. * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -157,7 +157,7 @@ private constructor( */ fun email(email: JsonField) = apply { body.email(email) } - /** TOTP secret for 2FA re-authentication */ + /** Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret. */ fun totpSecret(totpSecret: String) = apply { body.totpSecret(totpSecret) } /** @@ -357,7 +357,7 @@ private constructor( fun email(): Optional = email.getOptional("email") /** - * TOTP secret for 2FA re-authentication + * Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret. * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type * (e.g. if the server responded with an unexpected value). @@ -452,7 +452,7 @@ private constructor( */ fun email(email: JsonField) = apply { this.email = email } - /** TOTP secret for 2FA re-authentication */ + /** Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret. */ fun totpSecret(totpSecret: String) = totpSecret(JsonField.of(totpSecret)) /** diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/XAccount.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/XAccount.kt index 04099c8..2dbe4c9 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/XAccount.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/XAccount.kt @@ -79,10 +79,10 @@ private constructor( fun createdAt(): OffsetDateTime = createdAt.getRequired("createdAt") /** - * Derived connection health. `healthy` = session active. `needsReauth` = user must submit fresh + * 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. + * the account. `recovering` = cooldown ended; the account can reconnect on its next use. + * `temporaryIssue` = temporary connection problem; wait before the next use. * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -262,10 +262,10 @@ private constructor( fun createdAt(createdAt: JsonField) = apply { this.createdAt = createdAt } /** - * Derived connection health. `healthy` = session active. `needsReauth` = user must submit + * 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. + * X banned the account. `recovering` = cooldown ended; the account can reconnect on its + * next use. `temporaryIssue` = temporary connection problem; wait before the next use. */ fun health(health: Health) = health(JsonField.of(health)) @@ -435,10 +435,10 @@ private constructor( (if (cookiesObtainedAt.asKnown().isPresent) 1 else 0) /** - * Derived connection health. `healthy` = session active. `needsReauth` = user must submit fresh + * 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. + * the account. `recovering` = cooldown ended; the account can reconnect on its next use. + * `temporaryIssue` = temporary connection problem; wait before the next use. */ class Health @JsonCreator private constructor(private val value: JsonField) : Enum { diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/ComposeServiceAsync.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/ComposeServiceAsync.kt index a0c684e..74fe23e 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/ComposeServiceAsync.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/ComposeServiceAsync.kt @@ -30,9 +30,10 @@ interface ComposeServiceAsync { fun withOptions(modifier: Consumer): ComposeServiceAsync /** - * 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. */ fun create(params: ComposeCreateParams): CompletableFuture = create(params, RequestOptions.none()) diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/XServiceAsync.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/XServiceAsync.kt index 2226975..856d3ea 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/XServiceAsync.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/XServiceAsync.kt @@ -17,6 +17,7 @@ import com.x_twitter_scraper.api.models.x.XGetNotificationsParams import com.x_twitter_scraper.api.models.x.XGetNotificationsResponse import com.x_twitter_scraper.api.models.x.XGetTrendsParams import com.x_twitter_scraper.api.models.x.XGetTrendsResponse +import com.x_twitter_scraper.api.services.async.x.AccountConnectionAttemptServiceAsync import com.x_twitter_scraper.api.services.async.x.AccountConnectionChallengeServiceAsync import com.x_twitter_scraper.api.services.async.x.AccountServiceAsync import com.x_twitter_scraper.api.services.async.x.BookmarkServiceAsync @@ -71,6 +72,9 @@ interface XServiceAsync { /** Connected X account management */ fun accountConnectionChallenges(): AccountConnectionChallengeServiceAsync + /** Connected X account management */ + fun accountConnectionAttempts(): AccountConnectionAttemptServiceAsync + /** Look up, search, and analyze individual tweets */ fun bookmarks(): BookmarkServiceAsync @@ -209,6 +213,9 @@ interface XServiceAsync { /** Connected X account management */ fun accountConnectionChallenges(): AccountConnectionChallengeServiceAsync.WithRawResponse + /** Connected X account management */ + fun accountConnectionAttempts(): AccountConnectionAttemptServiceAsync.WithRawResponse + /** Look up, search, and analyze individual tweets */ fun bookmarks(): BookmarkServiceAsync.WithRawResponse diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/XServiceAsyncImpl.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/XServiceAsyncImpl.kt index 51809f2..2045d84 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/XServiceAsyncImpl.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/XServiceAsyncImpl.kt @@ -27,6 +27,8 @@ import com.x_twitter_scraper.api.models.x.XGetNotificationsParams import com.x_twitter_scraper.api.models.x.XGetNotificationsResponse import com.x_twitter_scraper.api.models.x.XGetTrendsParams import com.x_twitter_scraper.api.models.x.XGetTrendsResponse +import com.x_twitter_scraper.api.services.async.x.AccountConnectionAttemptServiceAsync +import com.x_twitter_scraper.api.services.async.x.AccountConnectionAttemptServiceAsyncImpl import com.x_twitter_scraper.api.services.async.x.AccountConnectionChallengeServiceAsync import com.x_twitter_scraper.api.services.async.x.AccountConnectionChallengeServiceAsyncImpl import com.x_twitter_scraper.api.services.async.x.AccountServiceAsync @@ -88,6 +90,10 @@ class XServiceAsyncImpl internal constructor(private val clientOptions: ClientOp AccountConnectionChallengeServiceAsyncImpl(clientOptions) } + private val accountConnectionAttempts: AccountConnectionAttemptServiceAsync by lazy { + AccountConnectionAttemptServiceAsyncImpl(clientOptions) + } + private val bookmarks: BookmarkServiceAsync by lazy { BookmarkServiceAsyncImpl(clientOptions) } private val lists: ListServiceAsync by lazy { ListServiceAsyncImpl(clientOptions) } @@ -123,6 +129,10 @@ class XServiceAsyncImpl internal constructor(private val clientOptions: ClientOp override fun accountConnectionChallenges(): AccountConnectionChallengeServiceAsync = accountConnectionChallenges + /** Connected X account management */ + override fun accountConnectionAttempts(): AccountConnectionAttemptServiceAsync = + accountConnectionAttempts + /** Look up, search, and analyze individual tweets */ override fun bookmarks(): BookmarkServiceAsync = bookmarks @@ -204,6 +214,11 @@ class XServiceAsyncImpl internal constructor(private val clientOptions: ClientOp AccountConnectionChallengeServiceAsyncImpl.WithRawResponseImpl(clientOptions) } + private val accountConnectionAttempts: + AccountConnectionAttemptServiceAsync.WithRawResponse by lazy { + AccountConnectionAttemptServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + private val bookmarks: BookmarkServiceAsync.WithRawResponse by lazy { BookmarkServiceAsyncImpl.WithRawResponseImpl(clientOptions) } @@ -245,6 +260,10 @@ class XServiceAsyncImpl internal constructor(private val clientOptions: ClientOp override fun accountConnectionChallenges(): AccountConnectionChallengeServiceAsync.WithRawResponse = accountConnectionChallenges + /** Connected X account management */ + override fun accountConnectionAttempts(): + AccountConnectionAttemptServiceAsync.WithRawResponse = accountConnectionAttempts + /** Look up, search, and analyze individual tweets */ override fun bookmarks(): BookmarkServiceAsync.WithRawResponse = bookmarks diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/AccountConnectionAttemptServiceAsync.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/AccountConnectionAttemptServiceAsync.kt new file mode 100644 index 0000000..a9b61f8 --- /dev/null +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/AccountConnectionAttemptServiceAsync.kt @@ -0,0 +1,128 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.x_twitter_scraper.api.services.async.x + +import com.x_twitter_scraper.api.core.ClientOptions +import com.x_twitter_scraper.api.core.RequestOptions +import com.x_twitter_scraper.api.core.http.HttpResponseFor +import com.x_twitter_scraper.api.models.x.accountconnectionattempts.AccountConnectionAttemptRetrieveParams +import com.x_twitter_scraper.api.models.x.accountconnectionattempts.AccountConnectionAttemptRetrieveResponse +import java.util.concurrent.CompletableFuture +import java.util.function.Consumer + +/** Connected X account management */ +interface AccountConnectionAttemptServiceAsync { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions(modifier: Consumer): AccountConnectionAttemptServiceAsync + + /** Get X account connection status */ + fun retrieve(id: String): CompletableFuture = + retrieve(id, AccountConnectionAttemptRetrieveParams.none()) + + /** @see retrieve */ + fun retrieve( + id: String, + params: AccountConnectionAttemptRetrieveParams = + AccountConnectionAttemptRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().id(id).build(), requestOptions) + + /** @see retrieve */ + fun retrieve( + id: String, + params: AccountConnectionAttemptRetrieveParams = + AccountConnectionAttemptRetrieveParams.none(), + ): CompletableFuture = + retrieve(id, params, RequestOptions.none()) + + /** @see retrieve */ + fun retrieve( + params: AccountConnectionAttemptRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see retrieve */ + fun retrieve( + params: AccountConnectionAttemptRetrieveParams + ): CompletableFuture = + retrieve(params, RequestOptions.none()) + + /** @see retrieve */ + fun retrieve( + id: String, + requestOptions: RequestOptions, + ): CompletableFuture = + retrieve(id, AccountConnectionAttemptRetrieveParams.none(), requestOptions) + + /** + * A view of [AccountConnectionAttemptServiceAsync] that provides access to raw HTTP responses + * for each method. + */ + interface WithRawResponse { + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions( + modifier: Consumer + ): AccountConnectionAttemptServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `get /x/account-connection-attempts/{id}`, but is + * otherwise the same as [AccountConnectionAttemptServiceAsync.retrieve]. + */ + fun retrieve( + id: String + ): CompletableFuture> = + retrieve(id, AccountConnectionAttemptRetrieveParams.none()) + + /** @see retrieve */ + fun retrieve( + id: String, + params: AccountConnectionAttemptRetrieveParams = + AccountConnectionAttemptRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().id(id).build(), requestOptions) + + /** @see retrieve */ + fun retrieve( + id: String, + params: AccountConnectionAttemptRetrieveParams = + AccountConnectionAttemptRetrieveParams.none(), + ): CompletableFuture> = + retrieve(id, params, RequestOptions.none()) + + /** @see retrieve */ + fun retrieve( + params: AccountConnectionAttemptRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see retrieve */ + fun retrieve( + params: AccountConnectionAttemptRetrieveParams + ): CompletableFuture> = + retrieve(params, RequestOptions.none()) + + /** @see retrieve */ + fun retrieve( + id: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + retrieve(id, AccountConnectionAttemptRetrieveParams.none(), requestOptions) + } +} diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/AccountConnectionAttemptServiceAsyncImpl.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/AccountConnectionAttemptServiceAsyncImpl.kt new file mode 100644 index 0000000..f73c399 --- /dev/null +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/AccountConnectionAttemptServiceAsyncImpl.kt @@ -0,0 +1,96 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.x_twitter_scraper.api.services.async.x + +import com.x_twitter_scraper.api.core.ClientOptions +import com.x_twitter_scraper.api.core.RequestOptions +import com.x_twitter_scraper.api.core.checkRequired +import com.x_twitter_scraper.api.core.handlers.errorBodyHandler +import com.x_twitter_scraper.api.core.handlers.errorHandler +import com.x_twitter_scraper.api.core.handlers.jsonHandler +import com.x_twitter_scraper.api.core.http.HttpMethod +import com.x_twitter_scraper.api.core.http.HttpRequest +import com.x_twitter_scraper.api.core.http.HttpResponse +import com.x_twitter_scraper.api.core.http.HttpResponse.Handler +import com.x_twitter_scraper.api.core.http.HttpResponseFor +import com.x_twitter_scraper.api.core.http.parseable +import com.x_twitter_scraper.api.core.prepareAsync +import com.x_twitter_scraper.api.models.x.accountconnectionattempts.AccountConnectionAttemptRetrieveParams +import com.x_twitter_scraper.api.models.x.accountconnectionattempts.AccountConnectionAttemptRetrieveResponse +import java.util.concurrent.CompletableFuture +import java.util.function.Consumer +import kotlin.jvm.optionals.getOrNull + +/** Connected X account management */ +class AccountConnectionAttemptServiceAsyncImpl +internal constructor(private val clientOptions: ClientOptions) : + AccountConnectionAttemptServiceAsync { + + private val withRawResponse: AccountConnectionAttemptServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): AccountConnectionAttemptServiceAsync.WithRawResponse = + withRawResponse + + override fun withOptions( + modifier: Consumer + ): AccountConnectionAttemptServiceAsync = + AccountConnectionAttemptServiceAsyncImpl( + clientOptions.toBuilder().apply(modifier::accept).build() + ) + + override fun retrieve( + params: AccountConnectionAttemptRetrieveParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // get /x/account-connection-attempts/{id} + withRawResponse().retrieve(params, requestOptions).thenApply { it.parse() } + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + AccountConnectionAttemptServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: Consumer + ): AccountConnectionAttemptServiceAsync.WithRawResponse = + AccountConnectionAttemptServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier::accept).build() + ) + + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: AccountConnectionAttemptRetrieveParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("x", "account-connection-attempts", params._pathParam(0)) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + } +} diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/ComposeService.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/ComposeService.kt index b567abb..a11d01a 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/ComposeService.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/ComposeService.kt @@ -30,9 +30,10 @@ interface ComposeService { fun withOptions(modifier: Consumer): ComposeService /** - * 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. */ fun create(params: ComposeCreateParams): ComposeCreateResponse = create(params, RequestOptions.none()) diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/XService.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/XService.kt index b6e90d4..c56ec4c 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/XService.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/XService.kt @@ -18,6 +18,7 @@ import com.x_twitter_scraper.api.models.x.XGetNotificationsParams import com.x_twitter_scraper.api.models.x.XGetNotificationsResponse import com.x_twitter_scraper.api.models.x.XGetTrendsParams import com.x_twitter_scraper.api.models.x.XGetTrendsResponse +import com.x_twitter_scraper.api.services.blocking.x.AccountConnectionAttemptService import com.x_twitter_scraper.api.services.blocking.x.AccountConnectionChallengeService import com.x_twitter_scraper.api.services.blocking.x.AccountService import com.x_twitter_scraper.api.services.blocking.x.BookmarkService @@ -71,6 +72,9 @@ interface XService { /** Connected X account management */ fun accountConnectionChallenges(): AccountConnectionChallengeService + /** Connected X account management */ + fun accountConnectionAttempts(): AccountConnectionAttemptService + /** Look up, search, and analyze individual tweets */ fun bookmarks(): BookmarkService @@ -200,6 +204,9 @@ interface XService { /** Connected X account management */ fun accountConnectionChallenges(): AccountConnectionChallengeService.WithRawResponse + /** Connected X account management */ + fun accountConnectionAttempts(): AccountConnectionAttemptService.WithRawResponse + /** Look up, search, and analyze individual tweets */ fun bookmarks(): BookmarkService.WithRawResponse diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/XServiceImpl.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/XServiceImpl.kt index 40052be..f1e41d7 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/XServiceImpl.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/XServiceImpl.kt @@ -27,6 +27,8 @@ import com.x_twitter_scraper.api.models.x.XGetNotificationsParams import com.x_twitter_scraper.api.models.x.XGetNotificationsResponse import com.x_twitter_scraper.api.models.x.XGetTrendsParams import com.x_twitter_scraper.api.models.x.XGetTrendsResponse +import com.x_twitter_scraper.api.services.blocking.x.AccountConnectionAttemptService +import com.x_twitter_scraper.api.services.blocking.x.AccountConnectionAttemptServiceImpl import com.x_twitter_scraper.api.services.blocking.x.AccountConnectionChallengeService import com.x_twitter_scraper.api.services.blocking.x.AccountConnectionChallengeServiceImpl import com.x_twitter_scraper.api.services.blocking.x.AccountService @@ -82,6 +84,10 @@ class XServiceImpl internal constructor(private val clientOptions: ClientOptions AccountConnectionChallengeServiceImpl(clientOptions) } + private val accountConnectionAttempts: AccountConnectionAttemptService by lazy { + AccountConnectionAttemptServiceImpl(clientOptions) + } + private val bookmarks: BookmarkService by lazy { BookmarkServiceImpl(clientOptions) } private val lists: ListService by lazy { ListServiceImpl(clientOptions) } @@ -117,6 +123,10 @@ class XServiceImpl internal constructor(private val clientOptions: ClientOptions override fun accountConnectionChallenges(): AccountConnectionChallengeService = accountConnectionChallenges + /** Connected X account management */ + override fun accountConnectionAttempts(): AccountConnectionAttemptService = + accountConnectionAttempts + /** Look up, search, and analyze individual tweets */ override fun bookmarks(): BookmarkService = bookmarks @@ -198,6 +208,11 @@ class XServiceImpl internal constructor(private val clientOptions: ClientOptions AccountConnectionChallengeServiceImpl.WithRawResponseImpl(clientOptions) } + private val accountConnectionAttempts: + AccountConnectionAttemptService.WithRawResponse by lazy { + AccountConnectionAttemptServiceImpl.WithRawResponseImpl(clientOptions) + } + private val bookmarks: BookmarkService.WithRawResponse by lazy { BookmarkServiceImpl.WithRawResponseImpl(clientOptions) } @@ -239,6 +254,10 @@ class XServiceImpl internal constructor(private val clientOptions: ClientOptions override fun accountConnectionChallenges(): AccountConnectionChallengeService.WithRawResponse = accountConnectionChallenges + /** Connected X account management */ + override fun accountConnectionAttempts(): AccountConnectionAttemptService.WithRawResponse = + accountConnectionAttempts + /** Look up, search, and analyze individual tweets */ override fun bookmarks(): BookmarkService.WithRawResponse = bookmarks diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/AccountConnectionAttemptService.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/AccountConnectionAttemptService.kt new file mode 100644 index 0000000..62749a1 --- /dev/null +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/AccountConnectionAttemptService.kt @@ -0,0 +1,130 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.x_twitter_scraper.api.services.blocking.x + +import com.google.errorprone.annotations.MustBeClosed +import com.x_twitter_scraper.api.core.ClientOptions +import com.x_twitter_scraper.api.core.RequestOptions +import com.x_twitter_scraper.api.core.http.HttpResponseFor +import com.x_twitter_scraper.api.models.x.accountconnectionattempts.AccountConnectionAttemptRetrieveParams +import com.x_twitter_scraper.api.models.x.accountconnectionattempts.AccountConnectionAttemptRetrieveResponse +import java.util.function.Consumer + +/** Connected X account management */ +interface AccountConnectionAttemptService { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions(modifier: Consumer): AccountConnectionAttemptService + + /** Get X account connection status */ + fun retrieve(id: String): AccountConnectionAttemptRetrieveResponse = + retrieve(id, AccountConnectionAttemptRetrieveParams.none()) + + /** @see retrieve */ + fun retrieve( + id: String, + params: AccountConnectionAttemptRetrieveParams = + AccountConnectionAttemptRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): AccountConnectionAttemptRetrieveResponse = + retrieve(params.toBuilder().id(id).build(), requestOptions) + + /** @see retrieve */ + fun retrieve( + id: String, + params: AccountConnectionAttemptRetrieveParams = + AccountConnectionAttemptRetrieveParams.none(), + ): AccountConnectionAttemptRetrieveResponse = retrieve(id, params, RequestOptions.none()) + + /** @see retrieve */ + fun retrieve( + params: AccountConnectionAttemptRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): AccountConnectionAttemptRetrieveResponse + + /** @see retrieve */ + fun retrieve( + params: AccountConnectionAttemptRetrieveParams + ): AccountConnectionAttemptRetrieveResponse = retrieve(params, RequestOptions.none()) + + /** @see retrieve */ + fun retrieve( + id: String, + requestOptions: RequestOptions, + ): AccountConnectionAttemptRetrieveResponse = + retrieve(id, AccountConnectionAttemptRetrieveParams.none(), requestOptions) + + /** + * A view of [AccountConnectionAttemptService] that provides access to raw HTTP responses for + * each method. + */ + interface WithRawResponse { + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions( + modifier: Consumer + ): AccountConnectionAttemptService.WithRawResponse + + /** + * Returns a raw HTTP response for `get /x/account-connection-attempts/{id}`, but is + * otherwise the same as [AccountConnectionAttemptService.retrieve]. + */ + @MustBeClosed + fun retrieve(id: String): HttpResponseFor = + retrieve(id, AccountConnectionAttemptRetrieveParams.none()) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + id: String, + params: AccountConnectionAttemptRetrieveParams = + AccountConnectionAttemptRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().id(id).build(), requestOptions) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + id: String, + params: AccountConnectionAttemptRetrieveParams = + AccountConnectionAttemptRetrieveParams.none(), + ): HttpResponseFor = + retrieve(id, params, RequestOptions.none()) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: AccountConnectionAttemptRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + params: AccountConnectionAttemptRetrieveParams + ): HttpResponseFor = + retrieve(params, RequestOptions.none()) + + /** @see retrieve */ + @MustBeClosed + fun retrieve( + id: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(id, AccountConnectionAttemptRetrieveParams.none(), requestOptions) + } +} diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/AccountConnectionAttemptServiceImpl.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/AccountConnectionAttemptServiceImpl.kt new file mode 100644 index 0000000..21ff973 --- /dev/null +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/AccountConnectionAttemptServiceImpl.kt @@ -0,0 +1,91 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.x_twitter_scraper.api.services.blocking.x + +import com.x_twitter_scraper.api.core.ClientOptions +import com.x_twitter_scraper.api.core.RequestOptions +import com.x_twitter_scraper.api.core.checkRequired +import com.x_twitter_scraper.api.core.handlers.errorBodyHandler +import com.x_twitter_scraper.api.core.handlers.errorHandler +import com.x_twitter_scraper.api.core.handlers.jsonHandler +import com.x_twitter_scraper.api.core.http.HttpMethod +import com.x_twitter_scraper.api.core.http.HttpRequest +import com.x_twitter_scraper.api.core.http.HttpResponse +import com.x_twitter_scraper.api.core.http.HttpResponse.Handler +import com.x_twitter_scraper.api.core.http.HttpResponseFor +import com.x_twitter_scraper.api.core.http.parseable +import com.x_twitter_scraper.api.core.prepare +import com.x_twitter_scraper.api.models.x.accountconnectionattempts.AccountConnectionAttemptRetrieveParams +import com.x_twitter_scraper.api.models.x.accountconnectionattempts.AccountConnectionAttemptRetrieveResponse +import java.util.function.Consumer +import kotlin.jvm.optionals.getOrNull + +/** Connected X account management */ +class AccountConnectionAttemptServiceImpl +internal constructor(private val clientOptions: ClientOptions) : AccountConnectionAttemptService { + + private val withRawResponse: AccountConnectionAttemptService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): AccountConnectionAttemptService.WithRawResponse = + withRawResponse + + override fun withOptions( + modifier: Consumer + ): AccountConnectionAttemptService = + AccountConnectionAttemptServiceImpl( + clientOptions.toBuilder().apply(modifier::accept).build() + ) + + override fun retrieve( + params: AccountConnectionAttemptRetrieveParams, + requestOptions: RequestOptions, + ): AccountConnectionAttemptRetrieveResponse = + // get /x/account-connection-attempts/{id} + withRawResponse().retrieve(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + AccountConnectionAttemptService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: Consumer + ): AccountConnectionAttemptService.WithRawResponse = + AccountConnectionAttemptServiceImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier::accept).build() + ) + + private val retrieveHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun retrieve( + params: AccountConnectionAttemptRetrieveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("x", "account-connection-attempts", params._pathParam(0)) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { retrieveHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } +} diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/LoopbackTestServer.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/LoopbackTestServer.kt index 03df6cc..29b4201 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/LoopbackTestServer.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/LoopbackTestServer.kt @@ -48,7 +48,17 @@ internal object LoopbackTestServer { } } - val response = "{}".toByteArray(StandardCharsets.UTF_8) + val responseBody = + if ( + exchange.requestURI.path.startsWith( + "/x/account-connection-attempts/" + ) + ) { + """{"id":"xatt_0123456789abcdef0123456789abcdef","object":"x_account_connection_attempt","pollAfterMs":3000,"status":"pending"}""" + } else { + "{}" + } + val response = responseBody.toByteArray(StandardCharsets.UTF_8) exchange.responseHeaders.set("Content-Type", "application/json") exchange.sendResponseHeaders(200, response.size.toLong()) exchange.responseBody.use { it.write(response) } diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/compose/ComposeCreateResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/compose/ComposeCreateResponseTest.kt index 78ecf44..81f5104 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/compose/ComposeCreateResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/compose/ComposeCreateResponseTest.kt @@ -145,6 +145,80 @@ internal class ComposeCreateResponseTest { .followUpQuestions(listOf("string", "string", "string", "string")) .intentUrl("https://example.com") .nextStep("nextStep") + .radarRecommendations( + listOf( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ) + ) .scorerWeights( listOf( ComposeCreateResponse.ComposePrepareResult.ScorerWeight.builder() @@ -392,6 +466,80 @@ internal class ComposeCreateResponseTest { .followUpQuestions(listOf("string", "string", "string", "string")) .intentUrl("https://example.com") .nextStep("nextStep") + .radarRecommendations( + listOf( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ) + ) .scorerWeights( listOf( ComposeCreateResponse.ComposePrepareResult.ScorerWeight.builder() diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/radar/RadarItemTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/radar/RadarItemTest.kt index d746d02..7561646 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/radar/RadarItemTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/radar/RadarItemTest.kt @@ -7,7 +7,6 @@ package com.x_twitter_scraper.api.models.radar import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.x_twitter_scraper.api.core.JsonValue import com.x_twitter_scraper.api.core.jsonMapper import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat @@ -25,7 +24,16 @@ internal class RadarItemTest { .language("en") .metadata( RadarItem.Metadata.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .author("author") + .contentUrl("https://example.com") + .estimatedDownvotes(0L) + .estimatedUpvotes(0L) + .numberComments(0L) + .score(0L) + .selftext("selftext") + .sourceFormat(RadarItem.Metadata.SourceFormat.HTML) + .subreddit("subreddit") + .upvoteRatio(0.0) .build() ) .publishedAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) @@ -46,7 +54,16 @@ internal class RadarItemTest { assertThat(radarItem.metadata()) .isEqualTo( RadarItem.Metadata.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .author("author") + .contentUrl("https://example.com") + .estimatedDownvotes(0L) + .estimatedUpvotes(0L) + .numberComments(0L) + .score(0L) + .selftext("selftext") + .sourceFormat(RadarItem.Metadata.SourceFormat.HTML) + .subreddit("subreddit") + .upvoteRatio(0.0) .build() ) assertThat(radarItem.publishedAt()).isEqualTo(OffsetDateTime.parse("2025-01-15T12:00:00Z")) @@ -71,7 +88,16 @@ internal class RadarItemTest { .language("en") .metadata( RadarItem.Metadata.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .author("author") + .contentUrl("https://example.com") + .estimatedDownvotes(0L) + .estimatedUpvotes(0L) + .numberComments(0L) + .score(0L) + .selftext("selftext") + .sourceFormat(RadarItem.Metadata.SourceFormat.HTML) + .subreddit("subreddit") + .upvoteRatio(0.0) .build() ) .publishedAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/radar/RadarRetrieveTrendingTopicsResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/radar/RadarRetrieveTrendingTopicsResponseTest.kt index bdc5eed..2d944a9 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/radar/RadarRetrieveTrendingTopicsResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/radar/RadarRetrieveTrendingTopicsResponseTest.kt @@ -7,7 +7,6 @@ package com.x_twitter_scraper.api.models.radar import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.x_twitter_scraper.api.core.JsonValue import com.x_twitter_scraper.api.core.jsonMapper import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat @@ -28,7 +27,16 @@ internal class RadarRetrieveTrendingTopicsResponseTest { .language("en") .metadata( RadarItem.Metadata.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .author("author") + .contentUrl("https://example.com") + .estimatedDownvotes(0L) + .estimatedUpvotes(0L) + .numberComments(0L) + .score(0L) + .selftext("selftext") + .sourceFormat(RadarItem.Metadata.SourceFormat.HTML) + .subreddit("subreddit") + .upvoteRatio(0.0) .build() ) .publishedAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) @@ -55,7 +63,16 @@ internal class RadarRetrieveTrendingTopicsResponseTest { .language("en") .metadata( RadarItem.Metadata.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .author("author") + .contentUrl("https://example.com") + .estimatedDownvotes(0L) + .estimatedUpvotes(0L) + .numberComments(0L) + .score(0L) + .selftext("selftext") + .sourceFormat(RadarItem.Metadata.SourceFormat.HTML) + .subreddit("subreddit") + .upvoteRatio(0.0) .build() ) .publishedAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) @@ -87,7 +104,16 @@ internal class RadarRetrieveTrendingTopicsResponseTest { .language("en") .metadata( RadarItem.Metadata.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) + .author("author") + .contentUrl("https://example.com") + .estimatedDownvotes(0L) + .estimatedUpvotes(0L) + .numberComments(0L) + .score(0L) + .selftext("selftext") + .sourceFormat(RadarItem.Metadata.SourceFormat.HTML) + .subreddit("subreddit") + .upvoteRatio(0.0) .build() ) .publishedAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveParamsTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveParamsTest.kt new file mode 100644 index 0000000..0e8ed4f --- /dev/null +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveParamsTest.kt @@ -0,0 +1,28 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.x_twitter_scraper.api.models.x.accountconnectionattempts + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class AccountConnectionAttemptRetrieveParamsTest { + + @Test + fun create() { + AccountConnectionAttemptRetrieveParams.builder() + .id("xatt_0123456789abcdef0123456789abcdef") + .build() + } + + @Test + fun pathParams() { + val params = + AccountConnectionAttemptRetrieveParams.builder() + .id("xatt_0123456789abcdef0123456789abcdef") + .build() + + assertThat(params._pathParam(0)).isEqualTo("xatt_0123456789abcdef0123456789abcdef") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } +} diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponseTest.kt new file mode 100644 index 0000000..676228c --- /dev/null +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponseTest.kt @@ -0,0 +1,237 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.x_twitter_scraper.api.models.x.accountconnectionattempts + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.x_twitter_scraper.api.core.JsonValue +import com.x_twitter_scraper.api.core.jsonMapper +import com.x_twitter_scraper.api.errors.XTwitterScraperInvalidDataException +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +internal class AccountConnectionAttemptRetrieveResponseTest { + + @Test + fun ofXAccountConnectionAttemptPending() { + val xAccountConnectionAttemptPending = + AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptPending.builder() + .id("xatt_0123456789abcdef0123456789abcdef") + .pollAfterMs(3000L) + .build() + + val accountConnectionAttemptRetrieveResponse = + AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionAttemptPending( + xAccountConnectionAttemptPending + ) + + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptPending()) + .contains(xAccountConnectionAttemptPending) + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptSuccess()) + .isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptFailed()) + .isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionChallenge()).isEmpty + } + + @Test + fun ofXAccountConnectionAttemptPendingRoundtrip() { + val jsonMapper = jsonMapper() + val accountConnectionAttemptRetrieveResponse = + AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionAttemptPending( + AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptPending.builder() + .id("xatt_0123456789abcdef0123456789abcdef") + .pollAfterMs(3000L) + .build() + ) + + val roundtrippedAccountConnectionAttemptRetrieveResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(accountConnectionAttemptRetrieveResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedAccountConnectionAttemptRetrieveResponse) + .isEqualTo(accountConnectionAttemptRetrieveResponse) + } + + @Test + fun ofXAccountConnectionAttemptSuccess() { + val xAccountConnectionAttemptSuccess = + AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptSuccess.builder() + .id("xatt_0123456789abcdef0123456789abcdef") + .build() + + val accountConnectionAttemptRetrieveResponse = + AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionAttemptSuccess( + xAccountConnectionAttemptSuccess + ) + + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptPending()) + .isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptSuccess()) + .contains(xAccountConnectionAttemptSuccess) + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptFailed()) + .isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionChallenge()).isEmpty + } + + @Test + fun ofXAccountConnectionAttemptSuccessRoundtrip() { + val jsonMapper = jsonMapper() + val accountConnectionAttemptRetrieveResponse = + AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionAttemptSuccess( + AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptSuccess.builder() + .id("xatt_0123456789abcdef0123456789abcdef") + .build() + ) + + val roundtrippedAccountConnectionAttemptRetrieveResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(accountConnectionAttemptRetrieveResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedAccountConnectionAttemptRetrieveResponse) + .isEqualTo(accountConnectionAttemptRetrieveResponse) + } + + @Test + fun ofXAccountConnectionAttemptFailed() { + val xAccountConnectionAttemptFailed = + AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptFailed.builder() + .id("xatt_0123456789abcdef0123456789abcdef") + .error("service_unavailable") + .retryable(true) + .reason("wrong_password") + .build() + + val accountConnectionAttemptRetrieveResponse = + AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionAttemptFailed( + xAccountConnectionAttemptFailed + ) + + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptPending()) + .isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptSuccess()) + .isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptFailed()) + .contains(xAccountConnectionAttemptFailed) + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionChallenge()).isEmpty + } + + @Test + fun ofXAccountConnectionAttemptFailedRoundtrip() { + val jsonMapper = jsonMapper() + val accountConnectionAttemptRetrieveResponse = + AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionAttemptFailed( + AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptFailed.builder() + .id("xatt_0123456789abcdef0123456789abcdef") + .error("service_unavailable") + .retryable(true) + .reason("wrong_password") + .build() + ) + + val roundtrippedAccountConnectionAttemptRetrieveResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(accountConnectionAttemptRetrieveResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedAccountConnectionAttemptRetrieveResponse) + .isEqualTo(accountConnectionAttemptRetrieveResponse) + } + + @Test + fun ofXAccountConnectionChallenge() { + val xAccountConnectionChallenge = + AccountConnectionAttemptRetrieveResponse.XAccountConnectionChallenge.builder() + .id("xch_8vGd8Y9JvH6dV0xA") + .expiresAt(OffsetDateTime.parse("2026-05-08T12:10:00Z")) + .message("Enter the email verification code to continue.") + .object_( + AccountConnectionAttemptRetrieveResponse.XAccountConnectionChallenge.Object + .X_ACCOUNT_CONNECTION_CHALLENGE + ) + .status( + AccountConnectionAttemptRetrieveResponse.XAccountConnectionChallenge.Status + .REQUIRES_EMAIL_CODE + ) + .username("elonmusk") + .build() + + val accountConnectionAttemptRetrieveResponse = + AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionChallenge( + xAccountConnectionChallenge + ) + + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptPending()) + .isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptSuccess()) + .isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptFailed()) + .isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionChallenge()) + .contains(xAccountConnectionChallenge) + } + + @Test + fun ofXAccountConnectionChallengeRoundtrip() { + val jsonMapper = jsonMapper() + val accountConnectionAttemptRetrieveResponse = + AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionChallenge( + AccountConnectionAttemptRetrieveResponse.XAccountConnectionChallenge.builder() + .id("xch_8vGd8Y9JvH6dV0xA") + .expiresAt(OffsetDateTime.parse("2026-05-08T12:10:00Z")) + .message("Enter the email verification code to continue.") + .object_( + AccountConnectionAttemptRetrieveResponse.XAccountConnectionChallenge.Object + .X_ACCOUNT_CONNECTION_CHALLENGE + ) + .status( + AccountConnectionAttemptRetrieveResponse.XAccountConnectionChallenge.Status + .REQUIRES_EMAIL_CODE + ) + .username("elonmusk") + .build() + ) + + val roundtrippedAccountConnectionAttemptRetrieveResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(accountConnectionAttemptRetrieveResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedAccountConnectionAttemptRetrieveResponse) + .isEqualTo(accountConnectionAttemptRetrieveResponse) + } + + enum class IncompatibleJsonShapeTestCase(val value: JsonValue) { + BOOLEAN(JsonValue.from(false)), + STRING(JsonValue.from("invalid")), + INTEGER(JsonValue.from(-1)), + FLOAT(JsonValue.from(3.14)), + ARRAY(JsonValue.from(listOf("invalid", "array"))), + } + + @ParameterizedTest + @EnumSource + fun incompatibleJsonShapeDeserializesToUnknown(testCase: IncompatibleJsonShapeTestCase) { + val accountConnectionAttemptRetrieveResponse = + jsonMapper() + .convertValue( + testCase.value, + jacksonTypeRef(), + ) + + val e = + assertThrows { + accountConnectionAttemptRetrieveResponse.validate() + } + assertThat(e).hasMessageStartingWith("Unknown ") + } +} diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateParamsTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateParamsTest.kt index 52d87f9..a09fe8e 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateParamsTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateParamsTest.kt @@ -16,8 +16,8 @@ internal class AccountCreateParamsTest { AccountCreateParams.builder() .email("account@example.invalid") .password("") - .username("your_x_username") .totpSecret("") + .username("your_x_username") .build() } @@ -27,24 +27,7 @@ internal class AccountCreateParamsTest { AccountCreateParams.builder() .email("account@example.invalid") .password("") - .username("your_x_username") .totpSecret("") - .build() - - val body = params._body() - - assertThat(body.email()).isEqualTo("account@example.invalid") - assertThat(body.password()).isEqualTo("") - assertThat(body.username()).isEqualTo("your_x_username") - assertThat(body.totpSecret()).contains("") - } - - @Test - fun bodyWithoutOptionalFields() { - val params = - AccountCreateParams.builder() - .email("account@example.invalid") - .password("") .username("your_x_username") .build() @@ -52,6 +35,7 @@ internal class AccountCreateParamsTest { assertThat(body.email()).isEqualTo("account@example.invalid") assertThat(body.password()).isEqualTo("") + assertThat(body.totpSecret()).isEqualTo("") assertThat(body.username()).isEqualTo("your_x_username") } } diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponseTest.kt index c28dfdb..4c0e2b3 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponseTest.kt @@ -8,7 +8,6 @@ package com.x_twitter_scraper.api.models.x.accounts import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.x_twitter_scraper.api.core.jsonMapper -import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -16,37 +15,13 @@ internal class AccountCreateResponseTest { @Test fun create() { - val accountCreateResponse = - AccountCreateResponse.builder() - .id("42") - .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) - .health(AccountCreateResponse.Health.HEALTHY) - .status("active") - .xUserId("9876543210") - .xUsername("elonmusk") - .build() - - assertThat(accountCreateResponse.id()).isEqualTo("42") - assertThat(accountCreateResponse.createdAt()) - .isEqualTo(OffsetDateTime.parse("2025-01-15T12:00:00Z")) - assertThat(accountCreateResponse.health()).isEqualTo(AccountCreateResponse.Health.HEALTHY) - assertThat(accountCreateResponse.status()).isEqualTo("active") - assertThat(accountCreateResponse.xUserId()).isEqualTo("9876543210") - assertThat(accountCreateResponse.xUsername()).isEqualTo("elonmusk") + val accountCreateResponse = AccountCreateResponse.builder().build() } @Test fun roundtrip() { val jsonMapper = jsonMapper() - val accountCreateResponse = - AccountCreateResponse.builder() - .id("42") - .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) - .health(AccountCreateResponse.Health.HEALTHY) - .status("active") - .xUserId("9876543210") - .xUsername("elonmusk") - .build() + val accountCreateResponse = AccountCreateResponse.builder().build() val roundtrippedAccountCreateResponse = jsonMapper.readValue( diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/async/x/AccountConnectionAttemptServiceAsyncTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/async/x/AccountConnectionAttemptServiceAsyncTest.kt new file mode 100644 index 0000000..0fbb524 --- /dev/null +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/async/x/AccountConnectionAttemptServiceAsyncTest.kt @@ -0,0 +1,26 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.x_twitter_scraper.api.services.async.x + +import com.x_twitter_scraper.api.client.okhttp.XTwitterScraperOkHttpClientAsync +import org.junit.jupiter.api.Test + +internal class AccountConnectionAttemptServiceAsyncTest { + + @Test + fun retrieve() { + val client = + XTwitterScraperOkHttpClientAsync.builder() + .apiKey("My API Key") + .bearerToken("My Bearer Token") + .baseUrl(com.x_twitter_scraper.api.LoopbackTestServer.baseUrl()) + .build() + val accountConnectionAttemptServiceAsync = client.x().accountConnectionAttempts() + + val accountConnectionAttemptFuture = + accountConnectionAttemptServiceAsync.retrieve("xatt_0123456789abcdef0123456789abcdef") + + val accountConnectionAttempt = accountConnectionAttemptFuture.get() + accountConnectionAttempt.validate() + } +} diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/async/x/AccountServiceAsyncTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/async/x/AccountServiceAsyncTest.kt index fad47f8..2c4493a 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/async/x/AccountServiceAsyncTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/async/x/AccountServiceAsyncTest.kt @@ -27,8 +27,8 @@ internal class AccountServiceAsyncTest { AccountCreateParams.builder() .email("account@example.invalid") .password("") - .username("your_x_username") .totpSecret("") + .username("your_x_username") .build() ) diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/blocking/x/AccountConnectionAttemptServiceTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/blocking/x/AccountConnectionAttemptServiceTest.kt new file mode 100644 index 0000000..0fd36a8 --- /dev/null +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/blocking/x/AccountConnectionAttemptServiceTest.kt @@ -0,0 +1,25 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.x_twitter_scraper.api.services.blocking.x + +import com.x_twitter_scraper.api.client.okhttp.XTwitterScraperOkHttpClient +import org.junit.jupiter.api.Test + +internal class AccountConnectionAttemptServiceTest { + + @Test + fun retrieve() { + val client = + XTwitterScraperOkHttpClient.builder() + .apiKey("My API Key") + .bearerToken("My Bearer Token") + .baseUrl(com.x_twitter_scraper.api.LoopbackTestServer.baseUrl()) + .build() + val accountConnectionAttemptService = client.x().accountConnectionAttempts() + + val accountConnectionAttempt = + accountConnectionAttemptService.retrieve("xatt_0123456789abcdef0123456789abcdef") + + accountConnectionAttempt.validate() + } +} diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/blocking/x/AccountServiceTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/blocking/x/AccountServiceTest.kt index 5ab525e..502e4e0 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/blocking/x/AccountServiceTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/blocking/x/AccountServiceTest.kt @@ -27,8 +27,8 @@ internal class AccountServiceTest { AccountCreateParams.builder() .email("account@example.invalid") .password("") - .username("your_x_username") .totpSecret("") + .username("your_x_username") .build() ) diff --git a/x-twitter-scraper-java-proguard-test/src/test/kotlin/com/x_twitter_scraper/api/proguard/ProGuardCompatibilityTest.kt b/x-twitter-scraper-java-proguard-test/src/test/kotlin/com/x_twitter_scraper/api/proguard/ProGuardCompatibilityTest.kt index bc7208f..3336f1a 100644 --- a/x-twitter-scraper-java-proguard-test/src/test/kotlin/com/x_twitter_scraper/api/proguard/ProGuardCompatibilityTest.kt +++ b/x-twitter-scraper-java-proguard-test/src/test/kotlin/com/x_twitter_scraper/api/proguard/ProGuardCompatibilityTest.kt @@ -263,6 +263,80 @@ internal class ProGuardCompatibilityTest { .followUpQuestions(listOf("string", "string", "string", "string")) .intentUrl("https://example.com") .nextStep("nextStep") + .radarRecommendations( + listOf( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation.builder() + .endpoint("endpoint") + .guidance("guidance") + .source( + ComposeCreateResponse.ComposePrepareResult.RadarRecommendation + .Source + .REDDIT + ) + .useFor("useFor") + .build(), + ) + ) .scorerWeights( listOf( ComposeCreateResponse.ComposePrepareResult.ScorerWeight.builder()