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 17ce684..f413d2c 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-typescript/compare/v0.6.2...v0.7.0) + +### Features + +* **api:** api update ([88d6bd0](https://github.com/Xquik-dev/x-twitter-scraper-typescript/commit/88d6bd0144e12dbe9137181104795e0cd26cb44e)) +* **api:** api update ([8dd7565](https://github.com/Xquik-dev/x-twitter-scraper-typescript/commit/8dd7565b670085b6ad7c09fc6dbcae0352aba9b7)) + ## 0.6.2 (2026-07-24) Full Changelog: [v0.6.1...v0.6.2](https://github.com/Xquik-dev/x-twitter-scraper-typescript/compare/v0.6.1...v0.6.2) diff --git a/api.md b/api.md index 50c38a9..6995c70 100644 --- a/api.md +++ b/api.md @@ -408,7 +408,7 @@ Types: Methods: -- client.x.accounts.create({ ...params }) -> AccountCreateResponse +- client.x.accounts.create({ ...params }) -> unknown - client.x.accounts.retrieve(id) -> XAccountDetail - client.x.accounts.list() -> AccountListResponse - client.x.accounts.delete(id) -> AccountDeleteResponse @@ -425,6 +425,16 @@ Methods: - client.x.accountConnectionChallenges.submit(id, { ...params }) -> AccountConnectionChallengeSubmitResponse +## AccountConnectionAttempts + +Types: + +- AccountConnectionAttemptRetrieveResponse + +Methods: + +- client.x.accountConnectionAttempts.retrieve(id) -> AccountConnectionAttemptRetrieveResponse + ## Bookmarks Types: diff --git a/package.json b/package.json index 43596bc..a3b3228 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "x-twitter-scraper", - "version": "0.6.2", + "version": "0.7.0", "description": "Xquik TypeScript SDK & agent Skills for X/Twitter data, automation, MCP & webhooks. Not affiliated with X Corp.", "author": "Xquik ", "types": "dist/index.d.ts", diff --git a/src/resources/compose.ts b/src/resources/compose.ts index a04a134..6c85ba7 100644 --- a/src/resources/compose.ts +++ b/src/resources/compose.ts @@ -13,10 +13,10 @@ import { RequestOptions } from '../internal/request-options'; */ export class Compose extends APIResource { /** - * 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. * * @example * ```ts @@ -63,6 +63,11 @@ export namespace ComposeCreateResponse { nextStep: string; + /** + * Sources and guidance for researching a fresh post angle. + */ + radarRecommendations: Array; + /** * Published signal names with unpublished weights as null. */ @@ -108,6 +113,25 @@ export namespace ComposeCreateResponse { multiplier: 'Production weight not published by X'; } + export interface RadarRecommendation { + /** + * Radar endpoint for this source. + */ + endpoint: string; + + /** + * Source-specific drafting guidance. + */ + guidance: string; + + source: 'reddit' | 'github' | 'trustmrr' | 'hacker_news' | 'google_trends' | 'wikipedia' | 'polymarket'; + + /** + * Current-topic research this source supports. + */ + useFor: string; + } + export interface ScorerWeight { /** * Signal direction and publication limit. diff --git a/src/resources/radar.ts b/src/resources/radar.ts index 071832d..def8d66 100644 --- a/src/resources/radar.ts +++ b/src/resources/radar.ts @@ -37,12 +37,26 @@ export interface RadarItem { createdAt: string; + /** + * BCP-47 language code. und means the source did not identify a language. + */ language: string; /** * 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 } @@ -50,9 +64,14 @@ export interface RadarItem { * - wikipedia: { views: number } * - trustmrr: { mrr, growthPercent, last30Days, total, customers, * activeSubscriptions, onSale, xHandle?, category?, askingPrice?, country?, - * growthMrrPercent?, multiple?, paymentProvider?, rank? } + * foundedDate?, googleSearchImpressionsLast30Days?, growthMrrPercent?, + * multiple?, paymentProvider?, profitMarginLast30Days?, rank?, + * revenuePerVisitor?, targetAudience?, visitorsLast30Days? } For the startup + * growth source, xHandle is the founder's X username without @. The rank field + * is the source's revenue rank. Result order represents reported 30-day + * revenue-growth rank. */ - metadata: { [key: string]: unknown }; + metadata: RadarItem.Metadata; publishedAt: string; @@ -71,11 +90,72 @@ export interface RadarItem { description?: string; + /** + * Source image. Startup growth items return the logo here. + */ imageUrl?: string; url?: string; } +export namespace RadarItem { + /** + * Source-specific fields. Shape varies per source: + * + * - reddit: { author, authorId?, subreddit, subredditId?, subredditSubscribers?, + * sourceFormat, score?, upvoteRatio?, estimatedUpvotes?, estimatedDownvotes?, + * numberComments?, numberCrossposts?, selftext?, contentUrl?, domain?, + * postHint?, linkFlairText?, distinguished?, totalAwardsReceived?, viewCount?, + * editedAt?, galleryImageUrls?, redditVideo?, archived?, contestMode?, + * isCrosspostable?, isMeta?, isNsfw?, isOriginalContent?, isRobotIndexable?, + * isSelf?, isSpoiler?, isVideo?, locked?, stickied? }. `score` is Reddit's + * public net score. Exact public upvote and downvote counts are not available. + * Estimated counts derive from the public score and upvote ratio, which Reddit + * may fuzz. Comment bodies are not included. Current items combine public + * listing discovery with server-rendered post data and use `sourceFormat: html`; + * `json` and `rss` remain for legacy rows. + * - github: { starsToday: number } + * - hacker_news: { points: number, numberComments: number } + * - google_trends: { approxTraffic: number } + * - polymarket: { volume24hr: number } + * - wikipedia: { views: number } + * - trustmrr: { mrr, growthPercent, last30Days, total, customers, + * activeSubscriptions, onSale, xHandle?, category?, askingPrice?, country?, + * foundedDate?, googleSearchImpressionsLast30Days?, growthMrrPercent?, + * multiple?, paymentProvider?, profitMarginLast30Days?, rank?, + * revenuePerVisitor?, targetAudience?, visitorsLast30Days? } For the startup + * growth source, xHandle is the founder's X username without @. The rank field + * is the source's revenue rank. Result order represents reported 30-day + * revenue-growth rank. + */ + export interface Metadata { + author?: string; + + contentUrl?: string; + + estimatedDownvotes?: number; + + estimatedUpvotes?: number; + + numberComments?: number; + + score?: number; + + selftext?: string; + + /** + * Current items use html. json and rss are retained for legacy rows. + */ + sourceFormat?: 'html' | 'json' | 'rss'; + + subreddit?: string; + + upvoteRatio?: number; + + [k: string]: unknown; + } +} + export interface RadarRetrieveTrendingTopicsResponse { hasMore: boolean; diff --git a/src/resources/x/account-connection-attempts.ts b/src/resources/x/account-connection-attempts.ts new file mode 100644 index 0000000..9da2e7e --- /dev/null +++ b/src/resources/x/account-connection-attempts.ts @@ -0,0 +1,100 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import { APIPromise } from '../../core/api-promise'; +import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; + +/** + * Connected X account management + */ +export class AccountConnectionAttempts extends APIResource { + /** + * Get X account connection status + * + * @example + * ```ts + * const accountConnectionAttempt = + * await client.x.accountConnectionAttempts.retrieve( + * 'xatt_0123456789abcdef0123456789abcdef', + * ); + * ``` + */ + retrieve(id: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/x/account-connection-attempts/${id}`, options); + } +} + +/** + * The connection is still in progress. + */ +export type AccountConnectionAttemptRetrieveResponse = + | AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptPending + | AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptSuccess + | AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptFailed + | AccountConnectionAttemptRetrieveResponse.XAccountConnectionChallenge; + +export namespace AccountConnectionAttemptRetrieveResponse { + /** + * The connection is still in progress. + */ + export interface XAccountConnectionAttemptPending { + id: string; + + object: 'x_account_connection_attempt'; + + pollAfterMs: number; + + status: 'pending'; + } + + /** + * The account connected successfully. + */ + export interface XAccountConnectionAttemptSuccess { + id: string; + + object: 'x_account_connection_attempt'; + + status: 'success'; + } + + /** + * The connection reached a final failure. + */ + export interface XAccountConnectionAttemptFailed { + id: string; + + error: string; + + object: 'x_account_connection_attempt'; + + retryable: boolean; + + status: 'failed'; + + reason?: string; + } + + /** + * Resumable account connection challenge. Submit the email code to finish the same + * connection attempt. + */ + export interface XAccountConnectionChallenge { + id: string; + + expiresAt: string; + + message: string; + + object: 'x_account_connection_challenge'; + + status: 'requires_email_code'; + + username: string; + } +} + +export declare namespace AccountConnectionAttempts { + export { type AccountConnectionAttemptRetrieveResponse as AccountConnectionAttemptRetrieveResponse }; +} diff --git a/src/resources/x/accounts.ts b/src/resources/x/accounts.ts index 4e04c1e..9a37631 100644 --- a/src/resources/x/accounts.ts +++ b/src/resources/x/accounts.ts @@ -21,12 +21,12 @@ export class Accounts extends APIResource { * const account = await client.x.accounts.create({ * email: 'account@example.invalid', * password: '', - * username: 'your_x_username', * totp_secret: '', + * username: 'your_x_username', * }); * ``` */ - create(body: AccountCreateParams, options?: RequestOptions): APIPromise { + create(body: AccountCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/x/accounts', { body, ...options }); } @@ -107,11 +107,11 @@ export interface XAccount { createdAt: string; /** - * Derived connection health. `healthy` = session active. `needsReauth` = user must + * Derived connection health. `healthy` = ready to use. `needsReauth` = user must * submit fresh credentials. `locked` = X locked the account; unlock on x.com - * first. `suspended` = X banned the account. `recovering` = past cooldown, will - * auto-retry on next use. `temporaryIssue` = temporary connection problem; retry - * shortly. + * first. `suspended` = X banned the account. `recovering` = cooldown ended; the + * account can reconnect on its next use. `temporaryIssue` = temporary connection + * problem; wait before the next use. */ health: 'healthy' | 'locked' | 'needsReauth' | 'recovering' | 'suspended' | 'temporaryIssue'; @@ -147,22 +147,7 @@ export interface XAccountDetail { updatedAt?: string; } -/** - * Sanitized X account summary returned by connect and reauth. - */ -export interface AccountCreateResponse { - id: string; - - createdAt: string; - - health: 'healthy' | 'locked' | 'needsReauth' | 'recovering' | 'suspended' | 'temporaryIssue'; - - status: string; - - xUserId: string; - - xUsername: string; -} +export type AccountCreateResponse = unknown; export interface AccountListResponse { accounts: Array; @@ -208,14 +193,14 @@ export interface AccountCreateParams { password: string; /** - * X username + * Authenticator App TOTP secret required for durable login */ - username: string; + totp_secret: string; /** - * TOTP secret for 2FA + * X username */ - totp_secret?: string; + username: string; } export interface AccountReauthParams { @@ -230,7 +215,7 @@ export interface AccountReauthParams { email?: string; /** - * TOTP secret for 2FA re-authentication + * Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret. */ totp_secret?: string; } diff --git a/src/resources/x/index.ts b/src/resources/x/index.ts index e31d88b..6b6a3dd 100644 --- a/src/resources/x/index.ts +++ b/src/resources/x/index.ts @@ -4,6 +4,10 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +export { + AccountConnectionAttempts, + type AccountConnectionAttemptRetrieveResponse, +} from './account-connection-attempts'; export { AccountConnectionChallenges, type AccountConnectionChallengeSubmitResponse, diff --git a/src/resources/x/x.ts b/src/resources/x/x.ts index 8fbaab7..8522aaf 100644 --- a/src/resources/x/x.ts +++ b/src/resources/x/x.ts @@ -6,6 +6,11 @@ import { APIResource } from '../../core/resource'; import * as Shared from '../shared'; +import * as AccountConnectionAttemptsAPI from './account-connection-attempts'; +import { + AccountConnectionAttemptRetrieveResponse, + AccountConnectionAttempts, +} from './account-connection-attempts'; import * as AccountConnectionChallengesAPI from './account-connection-challenges'; import { AccountConnectionChallengeSubmitParams, @@ -122,6 +127,8 @@ export class X extends APIResource { accounts: AccountsAPI.Accounts = new AccountsAPI.Accounts(this._client); accountConnectionChallenges: AccountConnectionChallengesAPI.AccountConnectionChallenges = new AccountConnectionChallengesAPI.AccountConnectionChallenges(this._client); + accountConnectionAttempts: AccountConnectionAttemptsAPI.AccountConnectionAttempts = + new AccountConnectionAttemptsAPI.AccountConnectionAttempts(this._client); bookmarks: BookmarksAPI.Bookmarks = new BookmarksAPI.Bookmarks(this._client); lists: ListsAPI.Lists = new ListsAPI.Lists(this._client); @@ -391,6 +398,7 @@ X.Profile = Profile; X.Communities = Communities; X.Accounts = Accounts; X.AccountConnectionChallenges = AccountConnectionChallenges; +X.AccountConnectionAttempts = AccountConnectionAttempts; X.Bookmarks = Bookmarks; X.Lists = Lists; @@ -505,6 +513,11 @@ export declare namespace X { type AccountConnectionChallengeSubmitParams as AccountConnectionChallengeSubmitParams, }; + export { + AccountConnectionAttempts as AccountConnectionAttempts, + type AccountConnectionAttemptRetrieveResponse as AccountConnectionAttemptRetrieveResponse, + }; + export { Bookmarks as Bookmarks, type BookmarkRetrieveFoldersResponse as BookmarkRetrieveFoldersResponse, diff --git a/src/version.ts b/src/version.ts index a46d3cc..60d945c 100644 --- a/src/version.ts +++ b/src/version.ts @@ -2,4 +2,4 @@ // // SPDX-License-Identifier: Apache-2.0 -export const VERSION = '0.6.2'; // x-release-please-version +export const VERSION = '0.7.0'; // x-release-please-version diff --git a/tests/api-resources/x/account-connection-attempts.test.ts b/tests/api-resources/x/account-connection-attempts.test.ts new file mode 100644 index 0000000..3ed495c --- /dev/null +++ b/tests/api-resources/x/account-connection-attempts.test.ts @@ -0,0 +1,25 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import XTwitterScraper from 'x-twitter-scraper'; + +const client = new XTwitterScraper({ + apiKey: 'My API Key', + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource accountConnectionAttempts', () => { + // Mock server tests are disabled + test.skip('retrieve', async () => { + const responsePromise = client.x.accountConnectionAttempts.retrieve( + 'xatt_0123456789abcdef0123456789abcdef', + ); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/x/accounts.test.ts b/tests/api-resources/x/accounts.test.ts index eda0966..ca06ea3 100644 --- a/tests/api-resources/x/accounts.test.ts +++ b/tests/api-resources/x/accounts.test.ts @@ -17,6 +17,7 @@ describe('resource accounts', () => { const responsePromise = client.x.accounts.create({ email: 'account@example.invalid', password: '', + totp_secret: '', username: 'your_x_username', }); const rawResponse = await responsePromise.asResponse(); @@ -32,8 +33,8 @@ describe('resource accounts', () => { const response = await client.x.accounts.create({ email: 'account@example.invalid', password: '', - username: 'your_x_username', totp_secret: '', + username: 'your_x_username', }); });