// ═══════════════════════════════════════════════════════════════════════════════ // XActions — TypeScript Type Declarations // The Complete X/Twitter Automation Toolkit // by nichxbt // ═══════════════════════════════════════════════════════════════════════════════ import type { Browser, Page } from 'puppeteer'; // ── Core Types ────────────────────────────────────────────────────────────── export interface BrowserOptions { headless?: boolean; proxy?: string; userDataDir?: string; args?: string[]; } export interface ScrapeOptions { limit?: number; format?: 'json' | 'csv'; output?: string; } // ── Profile ───────────────────────────────────────────────────────────────── export interface ScrapedProfile { name: string; username: string; bio: string; location?: string; website?: string; joinDate?: string; followers: number; following: number; tweets: number; verified: boolean; avatar?: string; header?: string; } // ── User ──────────────────────────────────────────────────────────────────── export interface User { name: string; username: string; bio?: string; followers?: number; following?: number; verified?: boolean; followsBack?: boolean; } // ── Tweet ─────────────────────────────────────────────────────────────────── export interface ScrapedTweet { id: string; text: string; author: string; authorUsername: string; timestamp: string; likes: number; retweets: number; replies: number; views?: number; url: string; media?: MediaItem[]; isRetweet?: boolean; isQuote?: boolean; quotedTweet?: ScrapedTweet; } export interface MediaItem { type: 'image' | 'video' | 'gif'; url: string; thumbnailUrl?: string; width?: number; height?: number; duration?: number; } // ── Thread ────────────────────────────────────────────────────────────────── export interface Thread { author: string; tweets: ScrapedTweet[]; totalTweets: number; text: string; } // ── Video ─────────────────────────────────────────────────────────────────── export interface VideoResult { url: string; variants: VideoVariant[]; thumbnail?: string; duration?: number; } export interface VideoVariant { url: string; bitrate?: number; contentType: string; } // ── Bookmark ──────────────────────────────────────────────────────────────── export interface Bookmark { tweet: ScrapedTweet; savedAt?: string; } // ── DM ────────────────────────────────────────────────────────────────────── export interface Conversation { id: string; participants: User[]; lastMessage: string; lastMessageTime: string; unread: boolean; } export interface DirectMessage { id: string; text: string; sender: string; recipient: string; timestamp: string; media?: MediaItem[]; } // ── Analytics ─────────────────────────────────────────────────────────────── export interface Analytics { followers: number; following: number; tweets: number; impressions?: number; profileVisits?: number; mentions?: number; period?: string; } export interface PostAnalytics { tweet: ScrapedTweet; impressions: number; engagements: number; engagementRate: number; likes: number; retweets: number; replies: number; clicks?: number; profileClicks?: number; } // ── Sentiment ─────────────────────────────────────────────────────────────── export interface SentimentResult { score: number; label: 'positive' | 'neutral' | 'negative'; confidence: number; keywords: string[]; } // ── Workflow ──────────────────────────────────────────────────────────────── export interface Workflow { id: string; name: string; description?: string; trigger: WorkflowTrigger; steps: WorkflowStep[]; enabled: boolean; createdAt: string; } export interface WorkflowTrigger { type: 'manual' | 'schedule' | 'webhook'; cron?: string; } export interface WorkflowStep { action?: string; target?: string; input?: string; output?: string; condition?: string; limit?: number; } export interface WorkflowResult { workflowId: string; status: 'success' | 'error' | 'partial'; steps: WorkflowStepResult[]; duration: number; } export interface WorkflowStepResult { step: number; action: string; status: 'success' | 'skipped' | 'error'; output?: unknown; error?: string; duration: number; } // ── Stream ────────────────────────────────────────────────────────────────── export interface Stream { id: string; type: 'tweet' | 'follower' | 'mention'; username: string; interval: number; status: 'active' | 'stopped'; pollCount: number; } // ── Reputation ────────────────────────────────────────────────────────────── export interface ReputationMonitor { id: string; target: string; type: 'mentions' | 'keyword' | 'replies'; interval: number; status: 'active' | 'stopped'; } export interface ReputationReport { username: string; period: string; sentimentDistribution: { positive: number; neutral: number; negative: number; }; topPositive: ScrapedTweet[]; topNegative: ScrapedTweet[]; timeline: Array<{ date: string; averageSentiment: number; count: number }>; keywords: Array<{ word: string; count: number }>; alerts: string[]; } // ── Export ─────────────────────────────────────────────────────────────────── export interface ExportResult { username: string; formats: string[]; files: string[]; stats: { profile: boolean; tweets: number; followers: number; following: number; bookmarks: number; }; } // ── Plugin ────────────────────────────────────────────────────────────────── export interface Plugin { name: string; version: string; description: string; tools?: unknown[]; scrapers?: Record; routes?: unknown[]; actions?: Record; } // ── Core Functions ────────────────────────────────────────────────────────── /** Launch a Puppeteer browser with stealth mode */ export function createBrowser(options?: BrowserOptions): Promise; /** Create a new stealth page in the browser */ export function createPage(browser: Browser): Promise; /** Scrape a user's profile data */ export function scrapeProfile(page: Page, username: string): Promise; /** Scrape a user's followers */ export function scrapeFollowers(page: Page, username: string, options?: ScrapeOptions): Promise; /** Scrape a user's following list */ export function scrapeFollowing(page: Page, username: string, options?: ScrapeOptions): Promise; /** Scrape a user's tweets */ export function scrapeTweets(page: Page, username: string, options?: ScrapeOptions): Promise; /** Search tweets by query */ export function searchTweets(page: Page, query: string, options?: ScrapeOptions): Promise; /** Log a page in with an X auth_token cookie */ export function loginWithCookie(page: Page, authToken: string): Promise; /** Scrape every tweet in a thread, starting from the given tweet URL */ export function scrapeThread(page: Page, tweetUrl: string): Promise; /** Scrape the accounts that liked a tweet */ export function scrapeLikes(page: Page, tweetUrl: string, options?: ScrapeOptions): Promise; /** Scrape recent tweets for a hashtag */ export function scrapeHashtag(page: Page, hashtag: string, options?: ScrapeOptions): Promise; /** Scrape the images and videos an account has posted */ export function scrapeMedia(page: Page, username: string, options?: ScrapeOptions): Promise; /** Scrape the members of an X List by its URL */ export function scrapeListMembers(page: Page, listUrl: string, options?: ScrapeOptions): Promise; /** Scrape the logged-in account's bookmarks */ export function scrapeBookmarks(page: Page, options?: ScrapeOptions): Promise; /** Scrape the logged-in account's notifications */ export function scrapeNotifications(page: Page, options?: ScrapeOptions): Promise; /** Scrape the trending topics for the logged-in account */ export function scrapeTrending(page: Page, options?: ScrapeOptions): Promise; /** Scrape the members of an X Community by its URL */ export function scrapeCommunityMembers(page: Page, communityUrl: string, options?: ScrapeOptions): Promise; /** Find live and scheduled X Spaces matching a search query */ export function scrapeSpaces(page: Page, query: string, options?: ScrapeOptions): Promise; /** Write data to a JSON file; resolves with the filename */ export function exportToJSON(data: unknown, filename: string): Promise; /** Write an array of flat records to a CSV file; resolves with the filename */ export function exportToCSV(data: Record[], filename: string): Promise; // ── Puppeteer scraper result shapes ───────────────────────────────────────── export interface ThreadTweet { id: string | null; text: string | null; timestamp: string | null; url: string | null; isMainAuthor: boolean; platform: 'twitter'; } export interface ScrapedMediaItem { type: 'image' | 'video'; url: string; tweetUrl?: string; tweetId?: string; platform?: 'twitter'; } export interface ScrapedNotification { text: string; time: string | null; links: string[]; platform: 'twitter'; } export interface ScrapedTrend { category: string | null; topic: string; posts: string | null; platform: 'twitter'; } export interface ScrapedSpace { title: string | null; host?: string | null; status?: string | null; link: string; platform: 'twitter'; } // ── Multi-platform scrape() and adapter system ────────────────────────────── export type PlatformName = 'twitter' | 'x' | 'bluesky' | 'bsky' | 'mastodon' | 'masto' | 'threads'; export type ScrapeAction = | 'profile' | 'followers' | 'following' | 'tweets' | 'posts' | 'search' | 'hashtag' | 'trending' | 'thread' | 'likes' | 'media' | 'listMembers' | 'bookmarks' | 'notifications' | 'communityMembers' | 'spaces' | 'feed'; export interface UnifiedScrapeOptions { /** Target username (profile, followers, following, tweets, media) */ username?: string; /** Search query (search action) */ query?: string; /** Hashtag without the leading # (hashtag action) */ hashtag?: string; /** Tweet, list, or community URL for URL-addressed actions */ url?: string; listUrl?: string; communityUrl?: string; /** Bluesky feed URI (feed action) */ feedUri?: string; /** Max results */ limit?: number; /** Mastodon instance URL */ instance?: string; /** Mastodon access token */ accessToken?: string; /** Bluesky service URL, handle, and app password */ service?: string; identifier?: string; password?: string; /** Existing Puppeteer page (Twitter, Threads); one is created when omitted */ page?: Page; /** Options for the browser that is auto-created when no page is given */ browserOptions?: BrowserOptions; /** X auth_token cookie applied to an auto-created page */ authToken?: string; /** Existing API client (Bluesky, Mastodon) */ client?: unknown; /** Close the auto-created browser when done (default true) */ autoClose?: boolean; [key: string]: unknown; } /** A platform module: every scraper it implements plus its browser/client factories */ export type PlatformModule = Record any>; /** Registry of platform modules, keyed by name and alias */ export declare const platforms: Record; /** Look up a platform module by name; throws on an unknown platform */ export function getPlatform(platform: string): PlatformModule; /** * Unified scrape entry point. Dispatches to the platform module and, when no * page or client is supplied, creates and tears down one for the call. */ export function scrape(platform: PlatformName | string, action: ScrapeAction | string, options?: UnifiedScrapeOptions): Promise; /** Resolve a plugin-contributed scraper's handler by name */ export function getPluginScraper(name: string): Promise; export interface AdapterDependencyStatus { available: boolean; message?: string; } export interface AdapterInfo { name: string; description?: string; supportsJavaScript?: boolean; requiresBrowser?: boolean; available: boolean; installHint?: string | null; error?: string; } /** * Base class for scraping-framework adapters (Puppeteer, Playwright, HTTP). * Subclass it and register the class with `registerAdapter`. */ export declare class BaseAdapter { name: string; description: string; supportsJavaScript: boolean; requiresBrowser: boolean; checkDependencies(): Promise; launch(options?: Record): Promise; newPage(browser: unknown, options?: Record): Promise; goto(page: unknown, url: string, options?: Record): Promise; evaluate(page: unknown, fn: (...args: any[]) => T, ...args: unknown[]): Promise; queryAll(page: unknown, selector: string, mapFn: (el: Element) => T): Promise; getContent(page: unknown): Promise; setCookie(page: unknown, cookie: CookieEntry): Promise; scroll(page: unknown, options?: Record): Promise; screenshot(page: unknown, options?: Record): Promise; waitForSelector(page: unknown, selector: string, options?: Record): Promise; closePage(page: unknown): Promise; closeBrowser(browser: unknown): Promise; getInfo(): Pick; } /** Get an adapter instance by name (defaults to the global default adapter) */ export function getAdapter(name?: string): Promise; /** Get the first adapter whose dependencies are installed, preferring the given name */ export function getAvailableAdapter(preferred?: string): Promise; /** Set the global default adapter name */ export function setDefaultAdapter(name: string): void; /** Read the global default adapter name */ export function getDefaultAdapterName(): string; /** Register an adapter class under a name */ export function registerAdapter(name: string, AdapterClass: typeof BaseAdapter): void; /** Names of every registered adapter */ export function listAdapters(): string[]; /** Info and availability for every registered adapter */ export function getAdapterInfo(): Promise; /** Dependency status keyed by adapter name */ export function checkAvailability(): Promise>; // ── HTTP scraper (direct GraphQL, no browser) ─────────────────────────────── export interface HttpScraperOptions { /** Browser cookie string for authentication, e.g. "auth_token=...; ct0=..." */ cookies?: string; /** HTTP or SOCKS5 proxy URL */ proxy?: string; /** How to handle rate limits: wait for the reset or throw */ rateLimitStrategy?: 'wait' | 'error'; [key: string]: unknown; } /** * Scraper returned by `createHttpScraper`: every HTTP scraper function with * the client argument already bound. */ export interface HttpScraper { client: unknown; scrapeProfile(username: string): Promise>; scrapeProfileById(userId: string): Promise>; parseUserData(raw: Record): Record; scrapeFollowers(username: string, options?: ScrapeOptions): Promise[]>; scrapeFollowing(username: string, options?: ScrapeOptions): Promise[]>; scrapeNonFollowers(username: string, options?: ScrapeOptions): Promise[]>; scrapeLikers(tweetId: string, options?: ScrapeOptions): Promise[]>; scrapeRetweeters(tweetId: string, options?: ScrapeOptions): Promise[]>; scrapeListMembers(listId: string, options?: ScrapeOptions): Promise[]>; scrapeTweets(username: string, options?: ScrapeOptions): Promise[]>; scrapeTweetsAndReplies(username: string, options?: ScrapeOptions): Promise[]>; scrapeTweetById(tweetId: string): Promise>; parseTweetData(raw: Record): Record; parseTimelineInstructions(instructions: unknown[]): Record[]; scrapeThread(tweetId: string, options?: Record): Promise[]>; scrapeFullThread(tweetId: string, options?: Record): Promise[]>; scrapeConversation(tweetId: string, options?: Record): Promise[]>; reconstructThread(tweets: Record[]): Record[]; parseConversationModule(module: Record): Record[]; postTweet(text: string, options?: Record): Promise>; postThread(tweets: string[], options?: Record): Promise[]>; deleteTweet(tweetId: string): Promise>; replyToTweet(tweetId: string, text: string, options?: Record): Promise>; quoteTweet(tweetId: string, text: string, options?: Record): Promise>; schedulePost(text: string, scheduledAt: Date | number | string, options?: Record): Promise>; likeTweet(tweetId: string): Promise>; unlikeTweet(tweetId: string): Promise>; retweet(tweetId: string): Promise>; unretweet(tweetId: string): Promise>; followUser(userId: string): Promise>; unfollowUser(userId: string): Promise>; followByUsername(username: string): Promise>; blockUser(userId: string): Promise>; unblockUser(userId: string): Promise>; muteUser(userId: string): Promise>; unmuteUser(userId: string): Promise>; bookmarkTweet(tweetId: string): Promise>; unbookmarkTweet(tweetId: string): Promise>; pinTweet(tweetId: string): Promise>; unpinTweet(tweetId: string): Promise>; bulkUnfollow(userIds: string[], options?: Record): Promise>; bulkLike(tweetIds: string[], options?: Record): Promise>; bulkBlock(userIds: string[], options?: Record): Promise>; uploadMedia(input: string | Buffer, options?: Record): Promise>; uploadImage(input: string | Buffer, options?: Record): Promise>; uploadVideo(input: string | Buffer, options?: Record): Promise>; uploadGif(input: string | Buffer, options?: Record): Promise>; setAltText(mediaId: string, altText: string): Promise>; scrapeMedia(username: string, options?: ScrapeOptions): Promise[]>; downloadMedia(url: string, options?: Record): Promise; getVideoUrl(tweetId: string): Promise; } /** Create an HTTP scraper (no browser) with every method bound to one client */ export function createHttpScraper(options?: HttpScraperOptions): Promise; // ── Scrapers Module ───────────────────────────────────────────────────────── export declare const scrapers: { createBrowser: typeof createBrowser; createPage: typeof createPage; loginWithCookie: typeof loginWithCookie; scrapeProfile: typeof scrapeProfile; scrapeFollowers: typeof scrapeFollowers; scrapeFollowing: typeof scrapeFollowing; scrapeTweets: typeof scrapeTweets; searchTweets: typeof searchTweets; scrapeThread: typeof scrapeThread; scrapeLikes: typeof scrapeLikes; scrapeHashtag: typeof scrapeHashtag; scrapeMedia: typeof scrapeMedia; scrapeListMembers: typeof scrapeListMembers; scrapeBookmarks: typeof scrapeBookmarks; scrapeNotifications: typeof scrapeNotifications; scrapeTrending: typeof scrapeTrending; scrapeCommunityMembers: typeof scrapeCommunityMembers; scrapeSpaces: typeof scrapeSpaces; exportToJSON: typeof exportToJSON; exportToCSV: typeof exportToCSV; scrape: typeof scrape; platforms: typeof platforms; getPlatform: typeof getPlatform; twitter: PlatformModule; bluesky: PlatformModule; mastodon: PlatformModule; threads: PlatformModule; getPluginScraper: typeof getPluginScraper; getAdapter: typeof getAdapter; getAvailableAdapter: typeof getAvailableAdapter; setDefaultAdapter: typeof setDefaultAdapter; getDefaultAdapterName: typeof getDefaultAdapterName; registerAdapter: typeof registerAdapter; listAdapters: typeof listAdapters; getAdapterInfo: typeof getAdapterInfo; checkAvailability: typeof checkAvailability; BaseAdapter: typeof BaseAdapter; }; // ── Managers ──────────────────────────────────────────────────────────────── export declare const articlePublisher: unknown; export declare const bookmarkManager: unknown; export declare const businessTools: unknown; export declare const creatorStudio: unknown; export declare const discoveryExplore: unknown; export declare const dmManager: unknown; export declare const engagementManager: unknown; export declare const grokIntegration: unknown; export declare const notificationManager: unknown; export declare const pollCreator: unknown; export declare const postComposer: unknown; export declare const premiumManager: unknown; export declare const profileManager: unknown; export declare const settingsManager: unknown; export declare const spacesManager: unknown; // ── Plugin System ─────────────────────────────────────────────────────────── export declare const plugins: unknown; export function initializePlugins(): Promise; export function installPlugin(name: string): Promise; export function removePlugin(name: string): Promise; export function listPlugins(): Plugin[]; export function getPluginTools(): unknown[]; export function getPluginScrapers(): Record; export function getPluginRoutes(): unknown[]; export function getPluginActions(): Record; // ── Browser Scripts Catalog ───────────────────────────────────────────────── export declare const browserScripts: Record; // ═══════════════════════════════════════════════════════════════════════════════ // HTTP Client (Track 01 — Programmatic Scraper) // No Puppeteer required. Uses Twitter's internal GraphQL API via HTTP. // ═══════════════════════════════════════════════════════════════════════════════ // ── Search Mode ───────────────────────────────────────────────────────────── export declare const SearchMode: { readonly Top: 'Top'; readonly Latest: 'Latest'; readonly Photos: 'Photos'; readonly Videos: 'Videos'; }; export type SearchModeType = typeof SearchMode[keyof typeof SearchMode]; // ── Scraper Options ───────────────────────────────────────────────────────── export interface ScraperOptions { /** Cookies string or array of {name, value} pairs */ cookies?: string | CookieEntry[]; /** Proxy URL (http, https, or socks5) */ proxy?: string; /** Custom fetch implementation */ fetch?: typeof globalThis.fetch; /** Request transform function applied before each request */ transform?: (request: RequestInit) => RequestInit | void; } export interface CookieEntry { name: string; value: string; domain?: string; path?: string; } export interface LoginCredentials { username: string; password: string; email?: string; } export interface SendTweetOptions { /** Media entity IDs to attach */ mediaIds?: string[]; /** Tweet ID to reply to */ replyTo?: string; } // ── Trend ─────────────────────────────────────────────────────────────────── export interface Trend { name: string; tweetCount: string; url: string; context: string; } // ── Poll ──────────────────────────────────────────────────────────────────── export interface PollOption { label: string; votes: number; } export interface Poll { id: string; options: PollOption[]; endDatetime: string | null; votingStatus: 'open' | 'closed'; totalVotes: number; } // ── Client Tweet Model ────────────────────────────────────────────────────── export interface ClientMediaItem { id: string; type: string; url: string; preview: string; width: number; height: number; duration: number | null; altText: string | null; } /** * Tweet data model returned by the HTTP client Scraper. * Created via `Tweet.fromGraphQL(raw)`. */ export declare class Tweet { id: string; text: string; fullText: string; username: string; userId: string; timeParsed: Date | null; timestamp: number | null; hashtags: string[]; mentions: string[]; urls: string[]; photos: Array<{ id: string; url: string; alt: string | null }>; videos: Array<{ id: string; url: string; preview: string; duration: number | null }>; thread: ClientTweet[]; inReplyToStatusId: string | null; inReplyToStatus: ClientTweet | null; quotedStatusId: string | null; quotedStatus: ClientTweet | null; isRetweet: boolean; isReply: boolean; isQuote: boolean; retweetedStatus: ClientTweet | null; likes: number; retweets: number; replies: number; views: number; bookmarkCount: number; place: Record | null; sensitiveContent: boolean; conversationId: string; poll: Poll | null; /** * Parse a tweet from a raw Twitter GraphQL "tweet_results.result" object. */ static fromGraphQL(raw: Record): Tweet | null; } /** @deprecated Use `Tweet`; kept for callers that imported the old alias */ export type ClientTweet = Tweet; // ── Client Profile Model ─────────────────────────────────────────────────── export interface Birthdate { day: number | null; month: number | null; year: number | null; visibility: string; } /** * User profile returned by the HTTP client Scraper. * Created via `Profile.fromGraphQL(raw)`. */ export declare class Profile { id: string; username: string; name: string; bio: string; location: string; website: string; joined: Date | null; followersCount: number; followingCount: number; tweetCount: number; likesCount: number; listedCount: number; mediaCount: number; avatar: string; banner: string; verified: boolean; protected: boolean; birthdate: Birthdate | null; pinnedTweetIds: string[]; isBlueVerified: boolean; isGovernment: boolean; isBusiness: boolean; affiliatesCount: number; canDm: boolean; platform: string; /** Full URL to profile on X */ readonly profileUrl: string; /** * Parse a profile from a raw Twitter GraphQL "user_results.result" object. */ static fromGraphQL(raw: Record): Profile | null; /** JSON-serializable representation */ toJSON(): Record; } /** @deprecated Use `Profile`; kept for callers that imported the old alias */ export type ClientProfile = Profile; // ── Client Message Model ─────────────────────────────────────────────────── /** * Direct message returned by the HTTP client Scraper. */ export declare class Message { id: string; text: string; senderId: string; recipientId: string; createdAt: Date | null; mediaUrls: string[]; conversationId: string; /** * Parse a DM from a raw Twitter inbox API entry. */ static fromRaw(raw: Record, conversationId?: string): Message | null; /** JSON-serializable representation */ toJSON(): Record; } /** @deprecated Use `Message`; kept for callers that imported the old alias */ export type ClientMessage = Message; /** * DM conversation object. */ export interface ClientConversation { id: string; type: 'ONE_TO_ONE' | 'GROUP_DM'; participantIds: string[]; lastMessage: Message | null; updatedAt: Date | null; } // ── Error Classes ─────────────────────────────────────────────────────────── /** * Base error for all XActions client errors. */ export declare class ScraperError extends Error { code: string; endpoint: string | null; httpStatus: number | null; rateLimitReset: number | null; timestamp: Date; constructor(message: string, code?: string, details?: Record); toString(): string; toJSON(): Record; } /** * Thrown when authentication fails or is required. */ export declare class AuthenticationError extends ScraperError { constructor(message: string, code?: string, details?: Record); } /** * Thrown when Twitter rate limits are exceeded. */ export declare class RateLimitError extends ScraperError { retryAfter: number | null; limit: number | null; remaining: number; resetAt: Date | null; readonly retryAfterMs: number; constructor(message?: string, details?: Record); } /** * Thrown when a requested resource does not exist. */ export declare class NotFoundError extends ScraperError { constructor(message: string, code?: string, details?: Record); } /** * Wraps raw Twitter API errors with structured metadata. */ export declare class TwitterApiError extends ScraperError { twitterErrorCode: number | null; twitterMessage: string | null; constructor(message: string, details?: Record); static fromTwitterError(error: Record, details?: Record): ScraperError; static fromResponse(body: Record, details?: Record): ScraperError; } // ── Scraper Class ─────────────────────────────────────────────────────────── /** * The main entry point for programmatic Twitter/X access via HTTP. * No Puppeteer or browser required. * * @example * ```js * import { Scraper, SearchMode } from 'xactions/client'; * * const scraper = new Scraper(); * await scraper.loadCookies('./cookies.json'); * const profile = await scraper.getProfile('elonmusk'); * for await (const tweet of scraper.getTweets('elonmusk', 20)) { * console.log(tweet.text); * } * ``` */ export declare class Scraper { constructor(options?: ScraperOptions); // ── Authentication ────────────────────────────────────────────────── /** Log in with credentials (placeholder — use cookie-based auth until Track 02) */ login(credentials: LoginCredentials): Promise; /** Log out and clear all auth state */ logout(): Promise; /** Check if the scraper is authenticated */ isLoggedIn(): Promise; /** Get current cookies */ getCookies(): Promise; /** Set cookies for authentication */ setCookies(cookies: CookieEntry[] | string): Promise; /** Save current cookies to a JSON file */ saveCookies(filePath: string): Promise; /** Load cookies from a JSON file */ loadCookies(filePath: string): Promise; // ── Users ─────────────────────────────────────────────────────────── /** Get a user's profile by screen name */ getProfile(username: string): Promise; /** Get the authenticated user's profile */ me(): Promise; /** Get a user's followers (requires userId, not username) */ getFollowers(userId: string, count?: number): AsyncGenerator; /** Get accounts a user follows */ getFollowing(userId: string, count?: number): AsyncGenerator; /** Follow a user by username */ followUser(username: string): Promise; /** Unfollow a user by username */ unfollowUser(username: string): Promise; // ── Tweets ────────────────────────────────────────────────────────── /** Get a single tweet by ID */ getTweet(id: string): Promise; /** Get tweets from a user's timeline */ getTweets(username: string, count?: number): AsyncGenerator; /** Get tweets and replies from a user's timeline */ getTweetsAndReplies(username: string, count?: number): AsyncGenerator; /** Get a user's liked tweets */ getLikedTweets(username: string, count?: number): AsyncGenerator; /** Get the latest tweet from a user */ getLatestTweet(username: string): Promise; /** Post a new tweet */ sendTweet(text: string, options?: SendTweetOptions): Promise; /** Post a quote tweet */ sendQuoteTweet(text: string, quotedTweetId: string, mediaIds?: string[]): Promise; /** Delete a tweet */ deleteTweet(id: string): Promise; /** Like a tweet */ likeTweet(id: string): Promise; /** Unlike a tweet */ unlikeTweet(id: string): Promise; /** Retweet a tweet */ retweet(id: string): Promise; /** Remove a retweet */ unretweet(id: string): Promise; // ── Search ────────────────────────────────────────────────────────── /** Search tweets with query and optional mode */ searchTweets(query: string, count?: number, mode?: SearchModeType): AsyncGenerator; /** Search user profiles */ searchProfiles(query: string, count?: number): AsyncGenerator; // ── Trends ────────────────────────────────────────────────────────── /** Get current trending topics */ getTrends(): Promise; // ── Lists ─────────────────────────────────────────────────────────── /** Get tweets from a Twitter List */ getListTweets(listId: string, count?: number): AsyncGenerator; // ── Direct Messages ───────────────────────────────────────────────── /** Send a direct message to a user by their numeric ID */ sendDm(userId: string, text: string): Promise; } // ── GraphQL Constants ─────────────────────────────────────────────────────── export declare const BEARER_TOKEN: string; export declare const DEFAULT_FEATURES: Record; export declare const GRAPHQL_ENDPOINTS: Record; export declare function buildGraphQLUrl( endpoint: { queryId: string; operationName: string }, variables: Record, features?: Record, fieldToggles?: Record, ): string; // ── Cookie Import (painless login) ──────────────────────────────────────────── /** A cookie parsed from an export or read from a browser database. */ export interface ImportedCookie { name: string; value: string; domain: string; path: string; secure: boolean; httpOnly: boolean; /** ISO 8601 expiry, or null when the cookie is a session cookie. */ expires: string | null; } /** Cookie export formats understood by parseCookieInput / detectCookieFormat. */ export type CookieFormat = 'json-array' | 'storage-state' | 'netscape' | 'header' | 'unknown'; /** Browsers readBrowserCookies can read cookies from. */ export type BrowserName = 'chrome' | 'chromium' | 'brave' | 'edge' | 'arc' | 'firefox'; export interface ParseCookieOptions { /** Force a format instead of auto-detecting. */ format?: CookieFormat | 'auto'; } /** * Parse cookie text in any supported format (Netscape cookies.txt, Cookie-Editor * / EditThisCookie JSON, Playwright / Puppeteer storageState, or a raw * "auth_token=...; ct0=..." header string) into X/Twitter cookies. * * @throws When the text is empty or contains no X/Twitter cookies. */ export function parseCookieInput(text: string, options?: ParseCookieOptions): ImportedCookie[]; /** Identify which cookie export format a blob of text is. */ export function detectCookieFormat(text: string): CookieFormat; /** * Read x.com cookies straight out of a locally installed browser. Supports * Firefox everywhere, and Chromium-family browsers on Linux (default key) and * macOS (Keychain). Throws an actionable Error naming the --cookies-file export * path for unsupported combinations. * * @throws On an unknown browser name or an unsupported platform/browser combo. */ export function readBrowserCookies(browser: BrowserName): ImportedCookie[]; /** Browsers readBrowserCookies understands. */ export const SUPPORTED_BROWSERS: BrowserName[]; // ============================================================================ // AI: prompt-driven comment generator (src/ai/commentGenerator.js) // ============================================================================ export type CommentProvider = 'openrouter' | 'openai' | 'xai' | 'anthropic' | 'ollama' | 'custom'; export interface CommentGeneratorConfig { /** How the replies should sound. Required. */ prompt: string; /** Optional first line of the system prompt, e.g. "You are @you, a founder building X". */ persona?: string; provider?: CommentProvider; apiKey?: string; /** Full chat-completions URL; required for provider "custom". */ baseUrl?: string; model?: string; temperature?: number; maxLength?: number; allowHashtags?: boolean; allowEmoji?: boolean; fetchImpl?: typeof fetch; } export interface CommentTweetInput { text: string; author?: string; authorName?: string; quotedText?: string; hasMedia?: boolean; } export interface GeneratedComment { text: string; model: string; /** 1 when the first completion was usable, 2 when it was regenerated for being generic. */ attempts: number; } export interface CommentGenerator { generate(tweet: CommentTweetInput): Promise; /** Replies produced so far in this session, fed back to the model for variety. */ history: string[]; target: { provider: string; url: string; model: string }; } export function createCommentGenerator(config: CommentGeneratorConfig): CommentGenerator; export function sanitizeComment(raw: string, opts?: { allowHashtags?: boolean; maxLength?: number }): string; export function isGenericComment(text: string): boolean; // ============================================================================ // AI: post reputation / risk scorer (src/ai/reputationScorer.js) // ============================================================================ export type RiskDimensionKey = 'professional' | 'hostile' | 'legal' | 'spam'; export type RiskVerdict = 'clean' | 'review' | 'flagged'; export interface RiskDimensionMeta { label: string; emoji: string; question: string; } /** The built-in risk dimensions, keyed by the name scorePost/scorePosts expect. */ export const DIMENSIONS: Record; export interface ScorablePost { id?: string; text: string; author?: string; authorName?: string; quotedText?: string; hasMedia?: boolean; isReply?: boolean; } export interface ReputationScoreConfig { provider?: CommentProvider; apiKey?: string; /** Full chat-completions URL; required for provider "custom". */ baseUrl?: string; model?: string; /** Subset of RiskDimensionKey to score. Default: all four. */ dimensions?: RiskDimensionKey[]; /** An extra risk question specific to this scan, scored alongside the built-ins. */ customQuestion?: string; /** Retries on 429/5xx before chatCompletion gives up. Default: 2. */ retries?: number; fetchImpl?: typeof fetch; } export interface ReputationScorePostsConfig extends ReputationScoreConfig { /** Parallel requests in flight, capped at 8. Default: 4. */ concurrency?: number; onProgress?: (done: number, total: number, result: PostRiskResult) => void; } export interface PostRiskResult { postId: string | null; dimensions: Record; /** The highest score across every scored dimension. */ overall: number; verdict: RiskVerdict; /** The dimension key that produced `overall`. */ worstDimension: string; model?: string; /** Present instead of the fields above when this post's scoring call failed. */ error?: string; } export interface ReputationReport { scanned: number; scoredOk: number; errors: number; /** 0..100, higher is better. */ reputationScore: number; grade: 'A+' | 'A' | 'B' | 'C' | 'D' | 'F'; verdictCounts: { clean: number; review: number; flagged: number }; /** Mean score per dimension across every successfully scored post. */ dimensionAverages: Record; /** Highest single-post score per dimension. Colour by this, not the average. */ dimensionPeaks: Record; worstPosts: Array<{ post: ScorablePost; score: PostRiskResult }>; } export function scorePost(post: ScorablePost, config?: ReputationScoreConfig): Promise; export function scorePosts(posts: ScorablePost[], config?: ReputationScorePostsConfig): Promise; export function scoreToGrade(reputationScore: number): 'A+' | 'A' | 'B' | 'C' | 'D' | 'F'; export function summarizeReport(posts: ScorablePost[], scores: PostRiskResult[], topN?: number): ReputationReport; // ============================================================================ // Signed outbound webhooks (src/notifications/webhook.js) // ============================================================================ export interface WebhookVerification { valid: boolean; /** Set when valid is false. */ reason?: string; /** Value of X-XActions-Event. */ event?: string; /** Value of X-XActions-Delivery. */ deliveryId?: string; /** Value of X-XActions-Timestamp, unix seconds. */ timestamp?: number; } export interface WebhookDeliveryAttempt { at: string; status: number | null; error?: string; durationMs: number; } export interface WebhookDeliveryRecord { id: string; url: string; event: string; /** Raw JSON body exactly as signed and sent. */ body: string; createdAt: string; completedAt?: string; status: 'delivered' | 'failed'; signed: boolean; attempts: WebhookDeliveryAttempt[]; replayOf?: string; } export interface DeliverWebhookOptions { url: string; payload: object | string; event?: string; /** Falls back to XACTIONS_WEBHOOK_SECRET. */ secret?: string; headers?: Record; id?: string; attempts?: number; baseDelayMs?: number; timeoutMs?: number; fetchImpl?: typeof fetch; } /** * Verify a webhook received from XActions: constant-time HMAC-SHA256 check of * the raw body against X-XActions-Signature, then the X-XActions-Timestamp * freshness window (default 300 seconds; pass toleranceSeconds: 0 to skip). */ export function verifyWebhookSignature( rawBody: string | Buffer, headers: Headers | Record, secret: string, options?: { toleranceSeconds?: number; now?: number }, ): WebhookVerification; /** "sha256=" HMAC-SHA256 of the raw body. */ export function signWebhookBody(rawBody: string | Buffer, secret: string): string; /** Sign and POST a webhook with retries; resolves with the delivery record either way. */ export function deliverWebhook(options: DeliverWebhookOptions): Promise; /** Re-send a logged delivery with a fresh timestamp and signature. */ export function replayWebhookDelivery( id: string, options?: Partial>, ): Promise; /** Deliveries from $XACTIONS_HOME/webhook-deliveries.json, newest first. */ export function listWebhookDeliveries(options?: { status?: 'delivered' | 'failed' | 'all'; limit?: number }): WebhookDeliveryRecord[];