{"version":3,"file":"dist-DotC-n5F.mjs","names":[],"sources":["../../../node_modules/.pnpm/@clawnch+clawnx@1.0.0/node_modules/@clawnch/clawnx/dist/clawnx.js"],"sourcesContent":["/**\n * ClawnX — X/Twitter API v2 client for AI agents\n *\n * Post tweets, search, read timelines, manage bookmarks, stream, chain\n * actions, and upload media — all from TypeScript with zero npm dependencies.\n *\n * Auth: OAuth 1.0a (HMAC-SHA1) for writes, Bearer token for reads.\n * Credentials are loaded from environment variables or passed directly.\n *\n * @example\n * ```typescript\n * import { ClawnX } from '@clawnch/clawnx';\n *\n * const x = new ClawnX();\n *\n * // Post a tweet\n * await x.postTweet({ text: 'Just launched $MYTKN on @clawnch!' });\n *\n * // Search for mentions of your token\n * const results = await x.searchTweets({ query: '$MYTKN' });\n *\n * // Upload media from a URL and post\n * const media = await x.uploadMediaFromUrl({ url: 'https://example.com/img.png' });\n * await x.postTweet({ text: 'Check this out!', mediaIds: [media.media_id_string] });\n *\n * // Stream filtered tweets\n * await x.setStreamRules([{ value: '$MYTKN', tag: 'token' }]);\n * const streamed = await x.streamFiltered({ durationMs: 30_000 });\n * ```\n */\nimport * as crypto from 'crypto';\nexport * from './clawnx-types.js';\nconst X_API_BASE = 'https://api.x.com/2';\n// ============================================================================\n// Helpers\n// ============================================================================\n/**\n * Extract a tweet ID from an x.com/twitter.com URL or raw numeric string.\n */\nexport function parseTweetId(input) {\n    const urlMatch = input.match(/(?:twitter\\.com|x\\.com)\\/\\w+\\/status\\/(\\d+)/);\n    if (urlMatch)\n        return urlMatch[1];\n    const stripped = input.trim();\n    if (/^\\d+$/.test(stripped))\n        return stripped;\n    throw new Error(`Invalid tweet ID or URL: ${input}`);\n}\n/**\n * Strip leading @ from a username.\n */\nexport function stripAt(username) {\n    return username.replace(/^@/, '');\n}\n// ============================================================================\n// OAuth 1.0a\n// ============================================================================\nfunction percentEncode(s) {\n    return encodeURIComponent(s).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);\n}\nfunction generateOAuthHeader(method, url, creds) {\n    const oauthParams = {\n        oauth_consumer_key: creds.apiKey,\n        oauth_nonce: crypto.randomBytes(16).toString('hex'),\n        oauth_signature_method: 'HMAC-SHA1',\n        oauth_timestamp: Math.floor(Date.now() / 1000).toString(),\n        oauth_token: creds.accessToken,\n        oauth_version: '1.0',\n    };\n    // Merge query string params for signature\n    const allParams = { ...oauthParams };\n    const parsed = new URL(url);\n    for (const [k, v] of parsed.searchParams.entries()) {\n        allParams[k] = v;\n    }\n    // Sort and build parameter string\n    const sortedEntries = Object.entries(allParams).sort(([a], [b]) => a.localeCompare(b));\n    const paramString = sortedEntries\n        .map(([k, v]) => `${percentEncode(k)}=${percentEncode(v)}`)\n        .join('&');\n    // Base URL (no query)\n    const baseUrl = `${parsed.protocol}//${parsed.host}${parsed.pathname}`;\n    // Signature base string\n    const baseString = `${method.toUpperCase()}&${percentEncode(baseUrl)}&${percentEncode(paramString)}`;\n    // Signing key\n    const signingKey = `${percentEncode(creds.apiSecret)}&${percentEncode(creds.accessTokenSecret)}`;\n    // HMAC-SHA1\n    const signature = crypto\n        .createHmac('sha1', signingKey)\n        .update(baseString)\n        .digest('base64');\n    oauthParams['oauth_signature'] = signature;\n    // Build Authorization header\n    const headerParts = Object.entries(oauthParams)\n        .sort(([a], [b]) => a.localeCompare(b))\n        .map(([k, v]) => `${percentEncode(k)}=\"${percentEncode(v)}\"`)\n        .join(', ');\n    return `OAuth ${headerParts}`;\n}\n// ============================================================================\n// Credential Loading\n// ============================================================================\nfunction loadCredentialsFromEnv() {\n    const get = (name) => {\n        const val = process.env[name];\n        if (!val) {\n            throw new Error(`Missing env var: ${name}. ` +\n                'Set X_API_KEY, X_API_SECRET, X_ACCESS_TOKEN, X_ACCESS_TOKEN_SECRET, X_BEARER_TOKEN ' +\n                'or pass credentials directly to ClawnX.');\n        }\n        return val;\n    };\n    return {\n        apiKey: get('X_API_KEY'),\n        apiSecret: get('X_API_SECRET'),\n        accessToken: get('X_ACCESS_TOKEN'),\n        accessTokenSecret: get('X_ACCESS_TOKEN_SECRET'),\n        bearerToken: get('X_BEARER_TOKEN'),\n    };\n}\n// ============================================================================\n// ClawnX Client\n// ============================================================================\nexport class ClawnX {\n    creds;\n    timeout;\n    _userId = null;\n    /** Active stream abort controller (one stream at a time) */\n    _streamController = null;\n    constructor(options = {}) {\n        this.creds = options.credentials ?? loadCredentialsFromEnv();\n        this.timeout = options.timeout ?? 30_000;\n    }\n    // ---------- internal transport ----------\n    async bearerGet(url) {\n        const controller = new AbortController();\n        const timer = setTimeout(() => controller.abort(), this.timeout);\n        try {\n            const resp = await fetch(url, {\n                method: 'GET',\n                headers: { Authorization: `Bearer ${this.creds.bearerToken}` },\n                signal: controller.signal,\n            });\n            return this.handle(resp);\n        }\n        finally {\n            clearTimeout(timer);\n        }\n    }\n    async oauthRequest(method, url, body) {\n        const authHeader = generateOAuthHeader(method, url, this.creds);\n        const headers = { Authorization: authHeader };\n        if (body)\n            headers['Content-Type'] = 'application/json';\n        const controller = new AbortController();\n        const timer = setTimeout(() => controller.abort(), this.timeout);\n        try {\n            const resp = await fetch(url, {\n                method,\n                headers,\n                body: body ? JSON.stringify(body) : undefined,\n                signal: controller.signal,\n            });\n            return this.handle(resp);\n        }\n        finally {\n            clearTimeout(timer);\n        }\n    }\n    async handle(resp) {\n        if (resp.status === 429) {\n            const reset = resp.headers.get('x-rate-limit-reset') ?? 'unknown';\n            throw new ClawnXError(`Rate limited. Resets at ${reset}.`, 429);\n        }\n        const data = await resp.json();\n        if (!resp.ok) {\n            const errors = data.errors ?? [];\n            const msg = errors.map((e) => e.detail ?? e.message ?? '').filter(Boolean).join('; ') ||\n                JSON.stringify(data).slice(0, 500);\n            throw new ClawnXError(`API error (HTTP ${resp.status}): ${msg}`, resp.status);\n        }\n        return data;\n    }\n    // ---------- authenticated user ----------\n    /**\n     * Get the numeric user ID for the authenticated account.\n     * Cached after first call.\n     */\n    async getAuthenticatedUserId() {\n        if (this._userId)\n            return this._userId;\n        const data = await this.oauthRequest('GET', `${X_API_BASE}/users/me`);\n        this._userId = data.data.id;\n        return this._userId;\n    }\n    // =========================================================================\n    // Tweet Operations\n    // =========================================================================\n    /**\n     * Post a tweet (or reply, quote, poll).\n     *\n     * @example\n     * ```typescript\n     * // Simple tweet\n     * await x.postTweet({ text: 'gm' });\n     *\n     * // Reply to a tweet\n     * await x.postTweet({ text: 'nice!', replyTo: '123456789' });\n     *\n     * // Quote tweet\n     * await x.postTweet({ text: 'check this out', quoteTweetId: '123456789' });\n     *\n     * // Poll\n     * await x.postTweet({ text: 'Which chain?', pollOptions: ['Base', 'Ethereum', 'Solana'] });\n     * ```\n     */\n    async postTweet(opts) {\n        const body = { text: opts.text };\n        if (opts.replyTo) {\n            body.reply = { in_reply_to_tweet_id: opts.replyTo };\n        }\n        if (opts.quoteTweetId) {\n            body.quote_tweet_id = opts.quoteTweetId;\n        }\n        if (opts.pollOptions) {\n            body.poll = {\n                options: opts.pollOptions,\n                duration_minutes: opts.pollDurationMinutes ?? 1440,\n            };\n        }\n        if (opts.mediaIds?.length) {\n            body.media = { media_ids: opts.mediaIds };\n        }\n        return this.oauthRequest('POST', `${X_API_BASE}/tweets`, body);\n    }\n    /**\n     * Delete a tweet.\n     * @param idOrUrl - Tweet ID or full URL\n     */\n    async deleteTweet(idOrUrl) {\n        const id = parseTweetId(idOrUrl);\n        return this.oauthRequest('DELETE', `${X_API_BASE}/tweets/${id}`);\n    }\n    /**\n     * Get a single tweet by ID or URL with full expansions.\n     * @param idOrUrl - Tweet ID or full URL\n     */\n    async getTweet(idOrUrl) {\n        const id = parseTweetId(idOrUrl);\n        const params = new URLSearchParams({\n            'tweet.fields': 'created_at,public_metrics,author_id,conversation_id,in_reply_to_user_id,referenced_tweets,attachments,entities,lang,note_tweet',\n            'expansions': 'author_id,referenced_tweets.id,attachments.media_keys',\n            'user.fields': 'name,username,verified,profile_image_url,public_metrics',\n            'media.fields': 'url,preview_image_url,type,width,height,alt_text',\n        });\n        return this.bearerGet(`${X_API_BASE}/tweets/${id}?${params}`);\n    }\n    /**\n     * Search recent tweets.\n     *\n     * Supports X query syntax: `from:user`, `$TICKER`, `#hashtag`,\n     * `\"exact phrase\"`, `has:media`, `is:reply`, `-is:retweet`, `lang:en`.\n     *\n     * @example\n     * ```typescript\n     * // Search for your token ticker\n     * const results = await x.searchTweets({ query: '$MYTKN' });\n     *\n     * // Search for tweets from a user\n     * const results = await x.searchTweets({ query: 'from:clawnch', maxResults: 20 });\n     * ```\n     */\n    async searchTweets(opts) {\n        const maxResults = Math.max(10, Math.min(opts.maxResults ?? 10, 100));\n        const params = new URLSearchParams({\n            query: opts.query,\n            max_results: maxResults.toString(),\n            'tweet.fields': 'created_at,public_metrics,author_id,conversation_id,entities,lang,note_tweet',\n            'expansions': 'author_id,attachments.media_keys',\n            'user.fields': 'name,username,verified,profile_image_url',\n            'media.fields': 'url,preview_image_url,type',\n        });\n        if (opts.paginationToken)\n            params.set('next_token', opts.paginationToken);\n        return this.bearerGet(`${X_API_BASE}/tweets/search/recent?${params}`);\n    }\n    /**\n     * Get tweet engagement metrics (requires OAuth — accesses non-public metrics).\n     * @param idOrUrl - Tweet ID or full URL\n     */\n    async getTweetMetrics(idOrUrl) {\n        const id = parseTweetId(idOrUrl);\n        const params = 'tweet.fields=public_metrics,non_public_metrics,organic_metrics';\n        return this.oauthRequest('GET', `${X_API_BASE}/tweets/${id}?${params}`);\n    }\n    // =========================================================================\n    // User Operations\n    // =========================================================================\n    /**\n     * Look up a user by username.\n     * @param username - Username (with or without @)\n     */\n    async getUser(username) {\n        const name = stripAt(username);\n        const fields = 'user.fields=created_at,description,public_metrics,verified,profile_image_url,url,location,pinned_tweet_id';\n        return this.bearerGet(`${X_API_BASE}/users/by/username/${name}?${fields}`);\n    }\n    /**\n     * Get a user's recent tweets.\n     * @param username - Username (with or without @)\n     */\n    async getUserTimeline(username, opts = {}) {\n        const userData = await this.getUser(username);\n        const userId = userData.data.id;\n        const maxResults = Math.max(5, Math.min(opts.maxResults ?? 10, 100));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'tweet.fields': 'created_at,public_metrics,author_id,conversation_id,entities,lang,note_tweet',\n            'expansions': 'author_id,attachments.media_keys,referenced_tweets.id',\n            'user.fields': 'name,username,verified',\n            'media.fields': 'url,preview_image_url,type',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.bearerGet(`${X_API_BASE}/users/${userId}/tweets?${params}`);\n    }\n    /**\n     * Get a user's followers.\n     * @param username - Username (with or without @)\n     */\n    async getFollowers(username, opts = {}) {\n        const userData = await this.getUser(username);\n        const userId = userData.data.id;\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 100, 1000));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'user.fields': 'created_at,description,public_metrics,verified,profile_image_url',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.bearerGet(`${X_API_BASE}/users/${userId}/followers?${params}`);\n    }\n    /**\n     * Get who a user follows.\n     * @param username - Username (with or without @)\n     */\n    async getFollowing(username, opts = {}) {\n        const userData = await this.getUser(username);\n        const userId = userData.data.id;\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 100, 1000));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'user.fields': 'created_at,description,public_metrics,verified,profile_image_url',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.bearerGet(`${X_API_BASE}/users/${userId}/following?${params}`);\n    }\n    // =========================================================================\n    // Self (Authenticated User)\n    // =========================================================================\n    /**\n     * Get your recent mentions.\n     */\n    async getMentions(opts = {}) {\n        const userId = await this.getAuthenticatedUserId();\n        const maxResults = Math.max(5, Math.min(opts.maxResults ?? 10, 100));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'tweet.fields': 'created_at,public_metrics,author_id,conversation_id,entities,note_tweet',\n            'expansions': 'author_id',\n            'user.fields': 'name,username,verified',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.oauthRequest('GET', `${X_API_BASE}/users/${userId}/mentions?${params}`);\n    }\n    // =========================================================================\n    // Engagement\n    // =========================================================================\n    /**\n     * Like a tweet.\n     * @param idOrUrl - Tweet ID or full URL\n     */\n    async likeTweet(idOrUrl) {\n        const tweetId = parseTweetId(idOrUrl);\n        const userId = await this.getAuthenticatedUserId();\n        return this.oauthRequest('POST', `${X_API_BASE}/users/${userId}/likes`, { tweet_id: tweetId });\n    }\n    /**\n     * Retweet a tweet.\n     * @param idOrUrl - Tweet ID or full URL\n     */\n    async retweet(idOrUrl) {\n        const tweetId = parseTweetId(idOrUrl);\n        const userId = await this.getAuthenticatedUserId();\n        return this.oauthRequest('POST', `${X_API_BASE}/users/${userId}/retweets`, { tweet_id: tweetId });\n    }\n    // =========================================================================\n    // Bookmarks\n    // =========================================================================\n    /**\n     * Get your bookmarks.\n     */\n    async getBookmarks(opts = {}) {\n        const userId = await this.getAuthenticatedUserId();\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 10, 100));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'tweet.fields': 'created_at,public_metrics,author_id,conversation_id,entities,lang,note_tweet',\n            'expansions': 'author_id,attachments.media_keys',\n            'user.fields': 'name,username,verified,profile_image_url',\n            'media.fields': 'url,preview_image_url,type',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.oauthRequest('GET', `${X_API_BASE}/users/${userId}/bookmarks?${params}`);\n    }\n    /**\n     * Bookmark a tweet.\n     * @param idOrUrl - Tweet ID or full URL\n     */\n    async bookmarkTweet(idOrUrl) {\n        const tweetId = parseTweetId(idOrUrl);\n        const userId = await this.getAuthenticatedUserId();\n        return this.oauthRequest('POST', `${X_API_BASE}/users/${userId}/bookmarks`, { tweet_id: tweetId });\n    }\n    /**\n     * Remove a bookmark.\n     * @param idOrUrl - Tweet ID or full URL\n     */\n    async unbookmarkTweet(idOrUrl) {\n        const tweetId = parseTweetId(idOrUrl);\n        const userId = await this.getAuthenticatedUserId();\n        return this.oauthRequest('DELETE', `${X_API_BASE}/users/${userId}/bookmarks/${tweetId}`);\n    }\n    // =========================================================================\n    // Undo Engagement\n    // =========================================================================\n    /**\n     * Unlike a tweet.\n     * @param idOrUrl - Tweet ID or full URL\n     */\n    async unlikeTweet(idOrUrl) {\n        const tweetId = parseTweetId(idOrUrl);\n        const userId = await this.getAuthenticatedUserId();\n        return this.oauthRequest('DELETE', `${X_API_BASE}/users/${userId}/likes/${tweetId}`);\n    }\n    /**\n     * Undo a retweet.\n     * @param idOrUrl - Tweet ID or full URL\n     */\n    async unretweet(idOrUrl) {\n        const tweetId = parseTweetId(idOrUrl);\n        const userId = await this.getAuthenticatedUserId();\n        return this.oauthRequest('DELETE', `${X_API_BASE}/users/${userId}/retweets/${tweetId}`);\n    }\n    // =========================================================================\n    // Engagement Lookups\n    // =========================================================================\n    /**\n     * Get users who liked a tweet.\n     * @param idOrUrl - Tweet ID or full URL\n     */\n    async getLikingUsers(idOrUrl, opts = {}) {\n        const id = parseTweetId(idOrUrl);\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 100, 100));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'user.fields': 'created_at,description,public_metrics,verified,profile_image_url',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.bearerGet(`${X_API_BASE}/tweets/${id}/liking_users?${params}`);\n    }\n    /**\n     * Get users who retweeted a tweet.\n     * @param idOrUrl - Tweet ID or full URL\n     */\n    async getRetweetedBy(idOrUrl, opts = {}) {\n        const id = parseTweetId(idOrUrl);\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 100, 100));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'user.fields': 'created_at,description,public_metrics,verified,profile_image_url',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.bearerGet(`${X_API_BASE}/tweets/${id}/retweeted_by?${params}`);\n    }\n    /**\n     * Get quote tweets for a tweet.\n     * @param idOrUrl - Tweet ID or full URL\n     */\n    async getQuoteTweets(idOrUrl, opts = {}) {\n        const id = parseTweetId(idOrUrl);\n        const maxResults = Math.max(10, Math.min(opts.maxResults ?? 10, 100));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'tweet.fields': 'created_at,public_metrics,author_id,entities,note_tweet',\n            'expansions': 'author_id',\n            'user.fields': 'name,username,verified',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.bearerGet(`${X_API_BASE}/tweets/${id}/quote_tweets?${params}`);\n    }\n    /**\n     * Get posts a user has liked.\n     * @param username - Username (with or without @)\n     */\n    async getLikedTweets(username, opts = {}) {\n        const userData = await this.getUser(username);\n        const userId = userData.data.id;\n        const maxResults = Math.max(10, Math.min(opts.maxResults ?? 10, 100));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'tweet.fields': 'created_at,public_metrics,author_id,entities,note_tweet',\n            'expansions': 'author_id',\n            'user.fields': 'name,username,verified',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.bearerGet(`${X_API_BASE}/users/${userId}/liked_tweets?${params}`);\n    }\n    // =========================================================================\n    // Follow / Unfollow\n    // =========================================================================\n    /**\n     * Follow a user.\n     * @param username - Username (with or without @)\n     */\n    async followUser(username) {\n        const targetData = await this.getUser(username);\n        const targetId = targetData.data.id;\n        const userId = await this.getAuthenticatedUserId();\n        return this.oauthRequest('POST', `${X_API_BASE}/users/${userId}/following`, { target_user_id: targetId });\n    }\n    /**\n     * Unfollow a user.\n     * @param username - Username (with or without @)\n     */\n    async unfollowUser(username) {\n        const targetData = await this.getUser(username);\n        const targetId = targetData.data.id;\n        const userId = await this.getAuthenticatedUserId();\n        return this.oauthRequest('DELETE', `${X_API_BASE}/users/${userId}/following/${targetId}`);\n    }\n    // =========================================================================\n    // Block / Unblock\n    // =========================================================================\n    /**\n     * Block a user.\n     * @param username - Username (with or without @)\n     */\n    async blockUser(username) {\n        const targetData = await this.getUser(username);\n        const targetId = targetData.data.id;\n        const userId = await this.getAuthenticatedUserId();\n        return this.oauthRequest('POST', `${X_API_BASE}/users/${userId}/blocking`, { target_user_id: targetId });\n    }\n    /**\n     * Unblock a user.\n     * @param username - Username (with or without @)\n     */\n    async unblockUser(username) {\n        const targetData = await this.getUser(username);\n        const targetId = targetData.data.id;\n        const userId = await this.getAuthenticatedUserId();\n        return this.oauthRequest('DELETE', `${X_API_BASE}/users/${userId}/blocking/${targetId}`);\n    }\n    /**\n     * Get users you have blocked.\n     */\n    async getBlockedUsers(opts = {}) {\n        const userId = await this.getAuthenticatedUserId();\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 100, 1000));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'user.fields': 'created_at,description,public_metrics,verified,profile_image_url',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.oauthRequest('GET', `${X_API_BASE}/users/${userId}/blocking?${params}`);\n    }\n    // =========================================================================\n    // Mute / Unmute\n    // =========================================================================\n    /**\n     * Mute a user.\n     * @param username - Username (with or without @)\n     */\n    async muteUser(username) {\n        const targetData = await this.getUser(username);\n        const targetId = targetData.data.id;\n        const userId = await this.getAuthenticatedUserId();\n        return this.oauthRequest('POST', `${X_API_BASE}/users/${userId}/muting`, { target_user_id: targetId });\n    }\n    /**\n     * Unmute a user.\n     * @param username - Username (with or without @)\n     */\n    async unmuteUser(username) {\n        const targetData = await this.getUser(username);\n        const targetId = targetData.data.id;\n        const userId = await this.getAuthenticatedUserId();\n        return this.oauthRequest('DELETE', `${X_API_BASE}/users/${userId}/muting/${targetId}`);\n    }\n    /**\n     * Get users you have muted.\n     */\n    async getMutedUsers(opts = {}) {\n        const userId = await this.getAuthenticatedUserId();\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 100, 1000));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'user.fields': 'created_at,description,public_metrics,verified,profile_image_url',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.oauthRequest('GET', `${X_API_BASE}/users/${userId}/muting?${params}`);\n    }\n    // =========================================================================\n    // User Lookups\n    // =========================================================================\n    /**\n     * Get the authenticated user's full profile.\n     */\n    async getMyProfile() {\n        const fields = 'user.fields=created_at,description,public_metrics,verified,profile_image_url,url,location,pinned_tweet_id';\n        return this.oauthRequest('GET', `${X_API_BASE}/users/me?${fields}`);\n    }\n    /**\n     * Look up multiple users by usernames.\n     * @param usernames - Array of usernames (with or without @, max 100)\n     */\n    async getUsersByUsernames(usernames) {\n        const names = usernames.map(stripAt).join(',');\n        const params = new URLSearchParams({\n            usernames: names,\n            'user.fields': 'created_at,description,public_metrics,verified,profile_image_url,url,location',\n        });\n        return this.bearerGet(`${X_API_BASE}/users/by?${params}`);\n    }\n    /**\n     * Look up multiple users by IDs.\n     * @param ids - Array of user IDs (max 100)\n     */\n    async getUsersByIds(ids) {\n        const params = new URLSearchParams({\n            ids: ids.join(','),\n            'user.fields': 'created_at,description,public_metrics,verified,profile_image_url,url,location',\n        });\n        return this.bearerGet(`${X_API_BASE}/users?${params}`);\n    }\n    /**\n     * Search for users by keyword.\n     * @param query - Search query\n     */\n    async searchUsers(query, opts = {}) {\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 20, 100));\n        const params = new URLSearchParams({\n            query,\n            max_results: maxResults.toString(),\n            'user.fields': 'created_at,description,public_metrics,verified,profile_image_url,url,location',\n        });\n        if (opts.paginationToken)\n            params.set('next_token', opts.paginationToken);\n        return this.bearerGet(`${X_API_BASE}/users/search?${params}`);\n    }\n    // =========================================================================\n    // Home Timeline\n    // =========================================================================\n    /**\n     * Get the authenticated user's home timeline (reverse chronological).\n     */\n    async getHomeTimeline(opts = {}) {\n        const userId = await this.getAuthenticatedUserId();\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 20, 100));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'tweet.fields': 'created_at,public_metrics,author_id,conversation_id,entities,lang,note_tweet',\n            'expansions': 'author_id,attachments.media_keys',\n            'user.fields': 'name,username,verified,profile_image_url',\n            'media.fields': 'url,preview_image_url,type',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.oauthRequest('GET', `${X_API_BASE}/users/${userId}/reverse_chronological_timeline?${params}`);\n    }\n    // =========================================================================\n    // Conversation Threads\n    // =========================================================================\n    /**\n     * Get the full reply thread for a tweet (using search by conversation_id).\n     * @param idOrUrl - Tweet ID or URL of the root tweet\n     */\n    async getConversation(idOrUrl, opts = {}) {\n        const rootTweet = await this.getTweet(idOrUrl);\n        const conversationId = rootTweet.data.conversation_id || rootTweet.data.id;\n        return this.searchTweets({\n            query: `conversation_id:${conversationId}`,\n            maxResults: opts.maxResults ?? 100,\n            paginationToken: opts.paginationToken,\n        });\n    }\n    // =========================================================================\n    // Thread Posting\n    // =========================================================================\n    /**\n     * Post a multi-tweet thread in one call.\n     *\n     * @example\n     * ```typescript\n     * const thread = await x.postThread([\n     *   { text: '1/ Announcing $MYTKN on @clawnch!' },\n     *   { text: '2/ We built this for the community.' },\n     *   { text: '3/ Trade now on Base.' },\n     * ]);\n     * console.log(thread.urls); // URLs for each tweet\n     * ```\n     */\n    async postThread(tweets) {\n        if (tweets.length === 0)\n            throw new ClawnXError('Thread must have at least one tweet', 0);\n        if (tweets.length > 25)\n            throw new ClawnXError('Thread cannot exceed 25 tweets', 0);\n        const tweetIds = [];\n        const urls = [];\n        let replyTo;\n        for (const tweet of tweets) {\n            const opts = {\n                text: tweet.text,\n                replyTo,\n                mediaIds: tweet.mediaIds,\n            };\n            // Only the first tweet can have a poll\n            if (!replyTo && tweet.pollOptions) {\n                opts.pollOptions = tweet.pollOptions;\n                opts.pollDurationMinutes = tweet.pollDurationMinutes;\n            }\n            const result = await this.postTweet(opts);\n            const id = result.data.id;\n            tweetIds.push(id);\n            urls.push(`https://x.com/i/status/${id}`);\n            replyTo = id;\n        }\n        return { tweetIds, urls };\n    }\n    // =========================================================================\n    // Lists\n    // =========================================================================\n    /**\n     * Create a new list.\n     */\n    async createList(opts) {\n        const body = { name: opts.name };\n        if (opts.description)\n            body.description = opts.description;\n        if (opts.private !== undefined)\n            body.private = opts.private;\n        return this.oauthRequest('POST', `${X_API_BASE}/lists`, body);\n    }\n    /**\n     * Delete a list you own.\n     * @param listId - List ID\n     */\n    async deleteList(listId) {\n        return this.oauthRequest('DELETE', `${X_API_BASE}/lists/${listId}`);\n    }\n    /**\n     * Update a list you own.\n     * @param listId - List ID\n     */\n    async updateList(listId, opts) {\n        const body = {};\n        if (opts.name !== undefined)\n            body.name = opts.name;\n        if (opts.description !== undefined)\n            body.description = opts.description;\n        if (opts.private !== undefined)\n            body.private = opts.private;\n        return this.oauthRequest('PUT', `${X_API_BASE}/lists/${listId}`, body);\n    }\n    /**\n     * Get a list by ID.\n     * @param listId - List ID\n     */\n    async getList(listId) {\n        const params = 'list.fields=created_at,follower_count,member_count,owner_id,description,private';\n        return this.bearerGet(`${X_API_BASE}/lists/${listId}?${params}`);\n    }\n    /**\n     * Get lists owned by a user.\n     * @param username - Username (with or without @)\n     */\n    async getUserLists(username, opts = {}) {\n        const userData = await this.getUser(username);\n        const userId = userData.data.id;\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 100, 100));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'list.fields': 'created_at,follower_count,member_count,owner_id,description,private',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.bearerGet(`${X_API_BASE}/users/${userId}/owned_lists?${params}`);\n    }\n    /**\n     * Add a user to a list.\n     * @param listId - List ID\n     * @param username - Username to add (with or without @)\n     */\n    async addListMember(listId, username) {\n        const targetData = await this.getUser(username);\n        return this.oauthRequest('POST', `${X_API_BASE}/lists/${listId}/members`, { user_id: targetData.data.id });\n    }\n    /**\n     * Remove a user from a list.\n     * @param listId - List ID\n     * @param username - Username to remove (with or without @)\n     */\n    async removeListMember(listId, username) {\n        const targetData = await this.getUser(username);\n        return this.oauthRequest('DELETE', `${X_API_BASE}/lists/${listId}/members/${targetData.data.id}`);\n    }\n    /**\n     * Get members of a list.\n     * @param listId - List ID\n     */\n    async getListMembers(listId, opts = {}) {\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 100, 100));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'user.fields': 'created_at,description,public_metrics,verified,profile_image_url',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.bearerGet(`${X_API_BASE}/lists/${listId}/members?${params}`);\n    }\n    /**\n     * Get tweets from a list.\n     * @param listId - List ID\n     */\n    async getListTweets(listId, opts = {}) {\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 25, 100));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'tweet.fields': 'created_at,public_metrics,author_id,entities,lang,note_tweet',\n            'expansions': 'author_id',\n            'user.fields': 'name,username,verified',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.bearerGet(`${X_API_BASE}/lists/${listId}/tweets?${params}`);\n    }\n    // =========================================================================\n    // Direct Messages\n    // =========================================================================\n    /**\n     * Send a DM to a user by username.\n     * @param username - Recipient username (with or without @)\n     * @param opts - Message options (text, optional mediaId)\n     */\n    async sendDM(username, opts) {\n        const targetData = await this.getUser(username);\n        const body = { text: opts.text };\n        if (opts.mediaId) {\n            body.attachments = [{ media_id: opts.mediaId }];\n        }\n        return this.oauthRequest('POST', `${X_API_BASE}/dm_conversations/with/${targetData.data.id}/messages`, body);\n    }\n    /**\n     * Send a DM to an existing conversation by conversation ID.\n     * @param conversationId - DM conversation ID\n     * @param opts - Message options\n     */\n    async sendDMToConversation(conversationId, opts) {\n        const body = { text: opts.text };\n        if (opts.mediaId) {\n            body.attachments = [{ media_id: opts.mediaId }];\n        }\n        return this.oauthRequest('POST', `${X_API_BASE}/dm_conversations/${conversationId}/messages`, body);\n    }\n    /**\n     * Get recent DM events across all conversations.\n     */\n    async getDMEvents(opts = {}) {\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 20, 100));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'dm_event.fields': 'id,event_type,text,sender_id,dm_conversation_id,created_at,attachments,referenced_tweets',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.oauthRequest('GET', `${X_API_BASE}/dm_events?${params}`);\n    }\n    /**\n     * Get DM events for a specific conversation.\n     * @param conversationId - DM conversation ID\n     */\n    async getDMConversation(conversationId, opts = {}) {\n        const maxResults = Math.max(1, Math.min(opts.maxResults ?? 20, 100));\n        const params = new URLSearchParams({\n            max_results: maxResults.toString(),\n            'dm_event.fields': 'id,event_type,text,sender_id,dm_conversation_id,created_at,attachments,referenced_tweets',\n        });\n        if (opts.paginationToken)\n            params.set('pagination_token', opts.paginationToken);\n        return this.oauthRequest('GET', `${X_API_BASE}/dm_conversations/${conversationId}/dm_events?${params}`);\n    }\n    // =========================================================================\n    // Media Upload\n    // =========================================================================\n    /**\n     * Upload media (image, GIF, or video) for attachment to tweets.\n     *\n     * Uses the v1.1 upload endpoint (upload.x.com) which is the standard\n     * path for media uploads even with API v2 tweets.\n     *\n     * @param mediaData - Base64-encoded media data or Buffer\n     * @param mimeType - MIME type (e.g. 'image/png', 'image/jpeg', 'image/gif', 'video/mp4')\n     * @returns MediaUploadResult with media_id_string to pass to postTweet\n     *\n     * @example\n     * ```typescript\n     * const media = await x.uploadMedia(imageBuffer, 'image/png');\n     * await x.postTweet({ text: 'Check this out!', mediaIds: [media.media_id_string] });\n     * ```\n     */\n    async uploadMedia(mediaData, mimeType, category) {\n        const UPLOAD_BASE = 'https://upload.x.com/1.1';\n        // Convert to base64 if Buffer\n        const base64Data = Buffer.isBuffer(mediaData)\n            ? mediaData.toString('base64')\n            : mediaData;\n        const totalBytes = Buffer.from(base64Data, 'base64').length;\n        // Determine media category from MIME type (or use caller override)\n        let mediaCategory = category ?? 'tweet_image';\n        if (!category) {\n            if (mimeType.startsWith('video/'))\n                mediaCategory = 'tweet_video';\n            else if (mimeType === 'image/gif')\n                mediaCategory = 'tweet_gif';\n        }\n        // INIT\n        const initResult = await this.oauthRequest('POST', `${UPLOAD_BASE}/media/upload.json?command=INIT&total_bytes=${totalBytes}&media_type=${encodeURIComponent(mimeType)}&media_category=${mediaCategory}`);\n        const mediaId = initResult.media_id_string;\n        // APPEND — chunked upload (max ~5MB per chunk)\n        const CHUNK_SIZE = 5 * 1024 * 1024; // 5MB\n        const rawBuffer = Buffer.from(base64Data, 'base64');\n        const totalChunks = Math.ceil(rawBuffer.length / CHUNK_SIZE);\n        for (let segment = 0; segment < totalChunks; segment++) {\n            const start = segment * CHUNK_SIZE;\n            const end = Math.min(start + CHUNK_SIZE, rawBuffer.length);\n            const chunkBase64 = rawBuffer.subarray(start, end).toString('base64');\n            const boundary = `----ClawnX${Date.now()}${segment}`;\n            const authHeader = generateOAuthHeader('POST', `${UPLOAD_BASE}/media/upload.json`, this.creds);\n            const bodyParts = [\n                `--${boundary}\\r\\nContent-Disposition: form-data; name=\"command\"\\r\\n\\r\\nAPPEND`,\n                `--${boundary}\\r\\nContent-Disposition: form-data; name=\"media_id\"\\r\\n\\r\\n${mediaId}`,\n                `--${boundary}\\r\\nContent-Disposition: form-data; name=\"segment_index\"\\r\\n\\r\\n${segment}`,\n                `--${boundary}\\r\\nContent-Disposition: form-data; name=\"media_data\"\\r\\n\\r\\n${chunkBase64}`,\n                `--${boundary}--`,\n            ].join('\\r\\n');\n            const ctrl = new AbortController();\n            const timer = setTimeout(() => ctrl.abort(), 120_000); // 2 min timeout per chunk\n            try {\n                const appendResp = await fetch(`${UPLOAD_BASE}/media/upload.json`, {\n                    method: 'POST',\n                    headers: {\n                        Authorization: authHeader,\n                        'Content-Type': `multipart/form-data; boundary=${boundary}`,\n                    },\n                    body: bodyParts,\n                    signal: ctrl.signal,\n                });\n                if (!appendResp.ok && appendResp.status !== 204) {\n                    const errText = await appendResp.text();\n                    throw new ClawnXError(`Media APPEND failed (chunk ${segment + 1}/${totalChunks}): ${errText}`, appendResp.status);\n                }\n            }\n            finally {\n                clearTimeout(timer);\n            }\n        }\n        // FINALIZE\n        const finalResult = await this.oauthRequest('POST', `${UPLOAD_BASE}/media/upload.json?command=FINALIZE&media_id=${mediaId}`);\n        // If video/GIF, poll for processing completion\n        if (finalResult.processing_info) {\n            let processing = finalResult.processing_info;\n            while (processing.state === 'pending' || processing.state === 'in_progress') {\n                const waitSecs = processing.check_after_secs ?? 5;\n                await new Promise((r) => setTimeout(r, waitSecs * 1000));\n                const status = await this.oauthRequest('GET', `${UPLOAD_BASE}/media/upload.json?command=STATUS&media_id=${mediaId}`);\n                processing = status.processing_info ?? { state: 'succeeded' };\n            }\n            if (processing.state === 'failed') {\n                throw new ClawnXError(`Media processing failed: ${processing.error?.message ?? 'unknown'}`, 0);\n            }\n        }\n        return finalResult;\n    }\n    // =========================================================================\n    // Media from URL (new in @clawnch/x)\n    // =========================================================================\n    /**\n     * Fetch media from a URL, upload it, and wait for processing.\n     *\n     * Combines three steps into one call:\n     * 1. Fetch media bytes from the URL\n     * 2. Upload via uploadMedia()\n     * 3. Poll for processing completion (videos/GIFs)\n     *\n     * @example\n     * ```typescript\n     * const media = await x.uploadMediaFromUrl({ url: 'https://example.com/chart.png' });\n     * await x.postTweet({ text: 'Daily chart', mediaIds: [media.media_id_string] });\n     * ```\n     */\n    async uploadMediaFromUrl(opts) {\n        const response = await fetch(opts.url);\n        if (!response.ok) {\n            throw new ClawnXError(`Failed to fetch media from ${opts.url}: ${response.status}`, response.status);\n        }\n        const buffer = Buffer.from(await response.arrayBuffer());\n        const mimeType = opts.mimeType ?? response.headers.get('content-type') ?? 'image/png';\n        return this.uploadMedia(buffer, mimeType, opts.mediaCategory);\n    }\n    // =========================================================================\n    // Streaming (new in @clawnch/x)\n    // =========================================================================\n    /**\n     * Connect to the X API v2 filtered stream and collect matching tweets.\n     *\n     * You must set stream rules first via `setStreamRules()`.\n     * The stream runs for `durationMs` or until `maxTweets` are collected.\n     *\n     * @example\n     * ```typescript\n     * await x.setStreamRules([{ value: '$MYTKN', tag: 'token' }]);\n     * const tweets = await x.streamFiltered({ durationMs: 30_000, maxTweets: 50 });\n     * console.log(`Collected ${tweets.length} matching tweets`);\n     * ```\n     */\n    async streamFiltered(opts = {}) {\n        const durationMs = opts.durationMs ?? 30_000;\n        const maxTweets = opts.maxTweets ?? 50;\n        const url = `${X_API_BASE}/tweets/search/stream?tweet.fields=created_at,public_metrics,author_id&expansions=author_id&user.fields=username`;\n        const controller = new AbortController();\n        this._streamController = controller;\n        const timeout = setTimeout(() => controller.abort(), durationMs);\n        const tweets = [];\n        try {\n            const response = await fetch(url, {\n                headers: { Authorization: `Bearer ${this.creds.bearerToken}` },\n                signal: controller.signal,\n            });\n            if (!response.ok) {\n                const errText = await response.text();\n                throw new ClawnXError(`Stream connection failed (${response.status}): ${errText}`, response.status);\n            }\n            if (!response.body)\n                throw new ClawnXError('No response body for stream', 0);\n            const reader = response.body.getReader();\n            const decoder = new TextDecoder();\n            let buffer = '';\n            while (tweets.length < maxTweets) {\n                const { done, value } = await reader.read();\n                if (done)\n                    break;\n                buffer += decoder.decode(value, { stream: true });\n                const lines = buffer.split('\\r\\n');\n                buffer = lines.pop() ?? '';\n                for (const line of lines) {\n                    if (!line.trim())\n                        continue; // heartbeat\n                    try {\n                        const parsed = JSON.parse(line);\n                        if (parsed.data)\n                            tweets.push(parsed.data);\n                    }\n                    catch {\n                        // skip malformed lines\n                    }\n                }\n            }\n        }\n        catch (err) {\n            if (err.name !== 'AbortError')\n                throw err;\n        }\n        finally {\n            clearTimeout(timeout);\n            this._streamController = null;\n        }\n        return tweets;\n    }\n    /**\n     * Stop the active filtered stream (if any).\n     * @returns true if a stream was stopped, false if none was active\n     */\n    stopStream() {\n        if (this._streamController) {\n            this._streamController.abort();\n            this._streamController = null;\n            return true;\n        }\n        return false;\n    }\n    /**\n     * Replace all stream filter rules with new ones.\n     * Deletes any existing rules first, then adds the new set.\n     *\n     * @example\n     * ```typescript\n     * await x.setStreamRules([\n     *   { value: '$MYTKN', tag: 'token' },\n     *   { value: 'from:clawnch', tag: 'official' },\n     * ]);\n     * ```\n     */\n    async setStreamRules(rules) {\n        const rulesUrl = `${X_API_BASE}/tweets/search/stream/rules`;\n        const authHeader = `Bearer ${this.creds.bearerToken}`;\n        const timeout = 30_000;\n        // Get existing rules\n        const getCtrl = new AbortController();\n        const getTimer = setTimeout(() => getCtrl.abort(), timeout);\n        try {\n            const getResp = await fetch(rulesUrl, {\n                headers: { Authorization: authHeader },\n                signal: getCtrl.signal,\n            });\n            if (!getResp.ok) {\n                throw new ClawnXError(`Failed to get stream rules: ${getResp.status}`, getResp.status);\n            }\n            const existing = await getResp.json();\n            // Delete existing rules if any\n            if (existing.data?.length > 0) {\n                const ids = existing.data.map((r) => r.id);\n                const delCtrl = new AbortController();\n                const delTimer = setTimeout(() => delCtrl.abort(), timeout);\n                try {\n                    const delResp = await fetch(rulesUrl, {\n                        method: 'POST',\n                        headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n                        body: JSON.stringify({ delete: { ids } }),\n                        signal: delCtrl.signal,\n                    });\n                    if (!delResp.ok) {\n                        throw new ClawnXError(`Failed to delete stream rules: ${delResp.status}`, delResp.status);\n                    }\n                }\n                finally {\n                    clearTimeout(delTimer);\n                }\n            }\n        }\n        finally {\n            clearTimeout(getTimer);\n        }\n        // Add new rules\n        const addCtrl = new AbortController();\n        const addTimer = setTimeout(() => addCtrl.abort(), timeout);\n        try {\n            const addResp = await fetch(rulesUrl, {\n                method: 'POST',\n                headers: { Authorization: authHeader, 'Content-Type': 'application/json' },\n                body: JSON.stringify({ add: rules }),\n                signal: addCtrl.signal,\n            });\n            if (!addResp.ok) {\n                const body = await addResp.text().catch(() => '');\n                throw new ClawnXError(`Failed to add stream rules: ${addResp.status} ${body}`, addResp.status);\n            }\n            const result = await addResp.json();\n            return (result.data ?? []);\n        }\n        finally {\n            clearTimeout(addTimer);\n        }\n    }\n    /**\n     * Get the current stream filter rules.\n     */\n    async getStreamRules() {\n        const ctrl = new AbortController();\n        const timer = setTimeout(() => ctrl.abort(), 30_000);\n        try {\n            const resp = await fetch(`${X_API_BASE}/tweets/search/stream/rules`, {\n                headers: { Authorization: `Bearer ${this.creds.bearerToken}` },\n                signal: ctrl.signal,\n            });\n            if (!resp.ok) {\n                throw new ClawnXError(`Failed to get stream rules: ${resp.status}`, resp.status);\n            }\n            const data = await resp.json();\n            return (data.data ?? []);\n        }\n        finally {\n            clearTimeout(timer);\n        }\n    }\n    // =========================================================================\n    // Action Chaining (new in @clawnch/x)\n    // =========================================================================\n    /**\n     * Execute a chain of actions sequentially with data flow between steps.\n     *\n     * Each step's parameters can use the special value `\"PREV_TWEET_ID\"` which\n     * is replaced with the tweet ID produced by the previous step. This enables\n     * post-then-like, post-then-retweet, and other compound workflows.\n     *\n     * @example\n     * ```typescript\n     * const result = await x.executeChain([\n     *   { action: 'postTweet', text: 'Just launched!' },\n     *   { action: 'likeTweet', idOrUrl: 'PREV_TWEET_ID' },\n     *   { action: 'retweet', idOrUrl: 'PREV_TWEET_ID' },\n     * ]);\n     * ```\n     */\n    async executeChain(steps) {\n        if (steps.length === 0) {\n            throw new ClawnXError('Chain must have at least one step', 0);\n        }\n        const results = [];\n        let prevTweetId;\n        let allSucceeded = true;\n        for (let i = 0; i < steps.length; i++) {\n            const { action, ...stepParams } = steps[i];\n            // Replace PREV_TWEET_ID placeholders\n            const resolvedParams = { ...stepParams };\n            for (const [key, val] of Object.entries(resolvedParams)) {\n                if (val === 'PREV_TWEET_ID') {\n                    if (!prevTweetId) {\n                        const error = `Step ${i + 1} references PREV_TWEET_ID but no previous step produced a tweet ID`;\n                        results.push({\n                            step: i,\n                            action,\n                            success: false,\n                            result: null,\n                            error,\n                        });\n                        return { success: false, steps: results, lastTweetId: prevTweetId };\n                    }\n                    resolvedParams[key] = prevTweetId;\n                }\n            }\n            try {\n                const tweetId = await this._executeChainStep(action, resolvedParams);\n                results.push({\n                    step: i,\n                    action,\n                    success: true,\n                    result: `OK`,\n                    tweetId: tweetId ?? undefined,\n                });\n                if (tweetId)\n                    prevTweetId = tweetId;\n            }\n            catch (err) {\n                allSucceeded = false;\n                results.push({\n                    step: i,\n                    action,\n                    success: false,\n                    result: null,\n                    error: err instanceof Error ? err.message : String(err),\n                });\n                // Stop chain on failure\n                break;\n            }\n        }\n        return { success: allSucceeded, steps: results, lastTweetId: prevTweetId };\n    }\n    /**\n     * Execute a single chain step and return the tweet ID if one was produced.\n     * Maps action names to ClawnX methods.\n     */\n    async _executeChainStep(action, params) {\n        switch (action) {\n            case 'postTweet': {\n                const result = await this.postTweet(params);\n                return result.data.id;\n            }\n            case 'postThread': {\n                const result = await this.postThread(params.tweets);\n                return result.tweetIds[0] ?? null;\n            }\n            case 'deleteTweet': {\n                await this.deleteTweet(params.idOrUrl);\n                return null;\n            }\n            case 'likeTweet': {\n                await this.likeTweet(params.idOrUrl);\n                return null;\n            }\n            case 'unlikeTweet': {\n                await this.unlikeTweet(params.idOrUrl);\n                return null;\n            }\n            case 'retweet': {\n                await this.retweet(params.idOrUrl);\n                return null;\n            }\n            case 'unretweet': {\n                await this.unretweet(params.idOrUrl);\n                return null;\n            }\n            case 'bookmarkTweet': {\n                await this.bookmarkTweet(params.idOrUrl);\n                return null;\n            }\n            case 'unbookmarkTweet': {\n                await this.unbookmarkTweet(params.idOrUrl);\n                return null;\n            }\n            case 'followUser': {\n                await this.followUser(params.username);\n                return null;\n            }\n            case 'unfollowUser': {\n                await this.unfollowUser(params.username);\n                return null;\n            }\n            case 'blockUser': {\n                await this.blockUser(params.username);\n                return null;\n            }\n            case 'unblockUser': {\n                await this.unblockUser(params.username);\n                return null;\n            }\n            case 'muteUser': {\n                await this.muteUser(params.username);\n                return null;\n            }\n            case 'unmuteUser': {\n                await this.unmuteUser(params.username);\n                return null;\n            }\n            case 'sendDM': {\n                await this.sendDM(params.username, { text: params.text });\n                return null;\n            }\n            case 'uploadMediaFromUrl': {\n                const result = await this.uploadMediaFromUrl({\n                    url: params.url,\n                    mimeType: params.mimeType,\n                    mediaCategory: params.mediaCategory,\n                });\n                // Store the media_id_string so chained postTweet can reference it\n                return result.media_id_string;\n            }\n            default:\n                throw new ClawnXError(`Unknown chain action: ${action}`, 0);\n        }\n    }\n}\n// ============================================================================\n// Error Class\n// ============================================================================\nexport class ClawnXError extends Error {\n    status;\n    constructor(message, status) {\n        super(message);\n        this.status = status;\n        this.name = 'ClawnXError';\n    }\n}\n//# sourceMappingURL=clawnx.js.map"],"x_google_ignoreList":[0],"mappings":"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"}