x-relay-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/x-relay/SKILL.md +130 -0
- package/README.md +21 -0
- package/dist/cli-DZkaLoUg.d.ts +232 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1958 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +123 -0
- package/dist/index.js +1977 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-shim.d.ts +11 -0
- package/dist/mcp-shim.js +1956 -0
- package/dist/mcp-shim.js.map +1 -0
- package/package.json +116 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/output.ts","../src/ids.ts","../src/engine/auth.ts","../src/engine/ops.ts","../src/engine/client.ts","../src/engine/cookies.ts","../src/engine/parse.ts","../src/engine/xctid/transaction.ts","../src/engine/xctid/cubic.ts","../src/engine/xctid/errors.ts","../src/engine/xctid/interpolate.ts","../src/engine/xctid/rotation.ts","../src/engine/xctid/utils.ts","../src/engine/index.ts","../src/commands/registry.ts","../src/cache/store.ts","../src/cache/search.ts","../src/cache/sync.ts","../src/commands/query.ts","../src/commands/runners.ts","../src/cli.ts"],"sourcesContent":["import type { Err, Ok } from './types.ts';\n\nexport function ok<T>(command: string, data: T): Ok<T> {\n return { ok: true, command, data };\n}\n\nexport function err(command: string, code: string, message: string, hint?: string): Err {\n const error: Err['error'] = hint !== undefined ? { code, message, hint } : { code, message };\n return { ok: false, command, error };\n}\n\nexport function toJson(envelope: unknown): string {\n return JSON.stringify(envelope, null, 2);\n}\n","// Pure extraction of a tweet id or a user handle from bare input or any\n// common X/Twitter URL form. No I/O.\n\n// Bare ids must look like a real snowflake (avoid matching stray short numbers);\n// an id pulled from an explicit `status/` segment can be any numeric run.\nconst BARE_TWEET_ID_RE = /^\\d{6,20}$/;\nconst PATH_TWEET_ID_RE = /^\\d{1,20}$/;\nconst HANDLE_RE = /^[A-Za-z0-9_]{1,15}$/;\n\nconst X_HOSTS = new Set([\n 'x.com',\n 'www.x.com',\n 'twitter.com',\n 'www.twitter.com',\n 'mobile.twitter.com',\n 'mobile.x.com',\n]);\n\n// Path segments that are routes, not usernames.\nconst RESERVED = new Set([\n 'i',\n 'home',\n 'search',\n 'explore',\n 'notifications',\n 'messages',\n 'settings',\n 'compose',\n 'hashtag',\n 'status',\n 'intent',\n 'share',\n 'login',\n 'signup',\n 'about',\n]);\n\nfunction parseUrl(input: string): URL | null {\n try {\n return new URL(input);\n } catch {\n return null;\n }\n}\n\n/** The canonical numeric tweet id from a bare id or any status URL, else null. */\nexport function extractTweetId(input: string): string | null {\n if (!input) return null;\n if (BARE_TWEET_ID_RE.test(input)) return input;\n\n const url = parseUrl(input);\n if (!url || !X_HOSTS.has(url.hostname)) return null;\n\n // Find the segment immediately after `status` (covers /user/status/<id> and\n // /i/web/status/<id>).\n const segments = url.pathname.split('/').filter(Boolean);\n const statusIdx = segments.indexOf('status');\n if (statusIdx === -1) return null;\n const id = segments[statusIdx + 1];\n return id !== undefined && PATH_TWEET_ID_RE.test(id) ? id : null;\n}\n\n/** A bare handle (no @) from @handle, a bare handle, or any profile/status URL. */\nexport function extractHandle(input: string): string | null {\n if (!input) return null;\n\n const bare = input.startsWith('@') ? input.slice(1) : input;\n if (HANDLE_RE.test(bare)) return bare;\n\n const url = parseUrl(input);\n if (!url || !X_HOSTS.has(url.hostname)) return null;\n\n const first = url.pathname.split('/').filter(Boolean)[0];\n if (first === undefined || RESERVED.has(first.toLowerCase())) return null;\n return HANDLE_RE.test(first) ? first : null;\n}\n","// Cookie parsing + the HTTP header builder for authenticated requests to X's\n// private GraphQL API. No I/O. See docs/ENGINE-RESEARCH.md §1.\n\n/** The two load-bearing cookies, plus any others the jar carries. */\nexport type Cookies = { authToken: string; ct0: string; extra?: Record<string, string> };\n\n// The hardcoded public web bearer token (docs/ENGINE-RESEARCH.md §1).\nexport const BEARER_TOKEN =\n 'AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA';\n\n// A realistic Chrome user-agent for a desktop session.\nconst USER_AGENT =\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36';\n\nfunction parseJsonForm(input: string): Record<string, string> | null {\n try {\n const parsed: unknown = JSON.parse(input);\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return null;\n const out: Record<string, string> = {};\n for (const [key, value] of Object.entries(parsed)) {\n out[key] = String(value);\n }\n return out;\n } catch {\n return null;\n }\n}\n\nfunction parsePairForm(input: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (const part of input.split(';')) {\n const eq = part.indexOf('=');\n if (eq === -1) continue;\n const key = part.slice(0, eq).trim();\n const value = part.slice(eq + 1).trim();\n if (key.length > 0) out[key] = value;\n }\n return out;\n}\n\n/**\n * Parse a browser cookie string (`auth_token=abc; ct0=def; ...`) or a JSON object\n * string (`{\"auth_token\":\"abc\",\"ct0\":\"def\"}`). Throws naming what's missing.\n */\nexport function parseCookies(input: string): Cookies {\n const jar = parseJsonForm(input.trim()) ?? parsePairForm(input);\n\n const authToken = jar.auth_token;\n const ct0 = jar.ct0;\n if (authToken === undefined) throw new Error('Missing cookie: auth_token');\n if (ct0 === undefined) throw new Error('Missing cookie: ct0');\n\n const extra: Record<string, string> = {};\n for (const [key, value] of Object.entries(jar)) {\n if (key !== 'auth_token' && key !== 'ct0') extra[key] = value;\n }\n\n const cookies: Cookies = { authToken, ct0 };\n if (Object.keys(extra).length > 0) cookies.extra = extra;\n return cookies;\n}\n\n/** Serialize to `auth_token=..; ct0=..[; k=v...]` — load-bearing cookies first. */\nexport function cookieString(cookies: Cookies): string {\n const parts = [`auth_token=${cookies.authToken}`, `ct0=${cookies.ct0}`];\n for (const [key, value] of Object.entries(cookies.extra ?? {})) {\n parts.push(`${key}=${value}`);\n }\n return parts.join('; ');\n}\n\n/** The full GraphQL request header set (docs/ENGINE-RESEARCH.md §1). */\nexport function buildHeaders(args: {\n cookies: Cookies;\n transactionId: string;\n clientLanguage?: string;\n}): Record<string, string> {\n const { cookies, transactionId, clientLanguage = 'en' } = args;\n return {\n authorization: `Bearer ${BEARER_TOKEN}`,\n 'x-csrf-token': cookies.ct0,\n 'x-twitter-auth-type': 'OAuth2Session',\n 'x-twitter-active-user': 'yes',\n 'x-twitter-client-language': clientLanguage,\n 'content-type': 'application/json',\n cookie: cookieString(cookies),\n 'x-client-transaction-id': transactionId,\n referer: 'https://x.com/',\n origin: 'https://x.com',\n 'sec-fetch-site': 'same-site',\n 'sec-fetch-mode': 'cors',\n 'sec-fetch-dest': 'empty',\n 'user-agent': USER_AGENT,\n accept: '*/*',\n 'accept-language': 'en-US,en;q=0.9',\n };\n}\n","// Externalized GraphQL operation config + request-building helpers for X/Twitter's\n// private GraphQL surface. See docs/ENGINE-RESEARCH.md §2. No I/O here — pure config +\n// pure request shaping. The network driver (client.ts) consumes these.\n//\n// URL shape: https://x.com/i/api/graphql/{queryId}/{OperationName}\n// Reads are GET with variables / features / fieldToggles JSON-stringified into query\n// params (see encodeParams). Builders replicate twscrape's kv/ft override ergonomics.\n\n/**\n * Operation name → { queryId, operationName }. Values are the twscrape mid-2026\n * snapshot from ENGINE-RESEARCH.md §2.\n *\n * IMPORTANT: query-ids ROTATE. They live here in config, never hardcoded in logic.\n * A `(336) features cannot be null` (or a 404 on the URL) means the hashes drifted —\n * refresh this config from the web bundle.\n */\nexport const OPS = {\n SearchTimeline: { queryId: 'Yw6L66Pw54NHKuq4Dp7b4Q', operationName: 'SearchTimeline' },\n UserByScreenName: { queryId: 'IGgvgiOx4QZndDHuD3x9TQ', operationName: 'UserByScreenName' },\n UserByRestId: { queryId: 'VQfQ9wwYdk6j_u2O4vt64Q', operationName: 'UserByRestId' },\n UserTweets: { queryId: '36rb3Xj3iJ64Q-9wKDjCcQ', operationName: 'UserTweets' },\n UserTweetsAndReplies: {\n queryId: 'D5eKzDa5ZoJuC1TCeAXbWA',\n operationName: 'UserTweetsAndReplies',\n },\n UserMedia: { queryId: '9EovraBTXJYGSEQXZqlLmQ', operationName: 'UserMedia' },\n Bookmarks: { queryId: 'XD0ViOeSOW4YoeNTGjVaYw', operationName: 'Bookmarks' },\n TweetDetail: { queryId: 'oCon7R-cgWRFy6EfZjaKfg', operationName: 'TweetDetail' },\n Followers: { queryId: '_orfRBQae57vylFPH0Huhg', operationName: 'Followers' },\n Following: { queryId: 'F42cDX8PDFxkbjjq6JrM2w', operationName: 'Following' },\n ListLatestTweetsTimeline: {\n queryId: '7UuJsFvnWuZo0HmxrzU42Q',\n operationName: 'ListLatestTweetsTimeline',\n },\n} as const satisfies Record<string, { queryId: string; operationName: string }>;\n\nexport type OpName = keyof typeof OPS;\n\n/**\n * The ~37-key GraphQL feature flags blob (twscrape `GQL_FEATURES` snapshot).\n *\n * IMPORTANT: these flags ROTATE. X rejects requests with missing/unknown keys with\n * `(336) The following features cannot be null`. Treat that response as a loud,\n * actionable failure (\"feature drift — refresh ops config\"), never silent — and\n * refresh this blob from the web bundle (don't hand-curate keys).\n */\nexport const FEATURES: Record<string, boolean> = {\n rweb_video_screen_enabled: false,\n profile_label_improvements_pcf_label_in_post_enabled: true,\n rweb_tipjar_consumption_enabled: true,\n responsive_web_graphql_exclude_directive_enabled: true,\n verified_phone_label_enabled: false,\n creator_subscriptions_tweet_preview_api_enabled: true,\n responsive_web_graphql_timeline_navigation_enabled: true,\n responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,\n premium_content_api_read_enabled: false,\n communities_web_enable_tweet_community_results_fetch: true,\n c9s_tweet_anatomy_moderator_badge_enabled: true,\n responsive_web_grok_analyze_button_fetch_trends_enabled: false,\n responsive_web_grok_analyze_post_followups_enabled: true,\n responsive_web_jetfuel_frame: false,\n responsive_web_grok_share_attachment_enabled: true,\n articles_preview_enabled: true,\n responsive_web_edit_tweet_api_enabled: true,\n graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,\n view_counts_everywhere_api_enabled: true,\n longform_notetweets_consumption_enabled: true,\n responsive_web_twitter_article_tweet_consumption_enabled: true,\n tweet_awards_web_tipping_enabled: false,\n responsive_web_grok_show_grok_translated_post: false,\n responsive_web_grok_analysis_button_from_backend: true,\n creator_subscriptions_quote_tweet_preview_enabled: false,\n freedom_of_speech_not_reach_fetch_enabled: true,\n standardized_nudges_misinfo: true,\n tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,\n longform_notetweets_rich_text_read_enabled: true,\n longform_notetweets_inline_media_enabled: true,\n responsive_web_grok_image_annotation_enabled: true,\n responsive_web_grok_imagine_annotation_enabled: true,\n responsive_web_grok_community_note_auto_translation_is_enabled: false,\n payments_enabled: false,\n hidden_profile_subscriptions_enabled: true,\n subscriptions_verification_info_is_identity_verified_enabled: true,\n subscriptions_verification_info_verified_since_enabled: true,\n responsive_web_enhance_cards_enabled: false,\n};\n\n/** The query string URL for a GraphQL operation (no params). */\nexport function graphqlUrl(op: OpName): string {\n const { queryId, operationName } = OPS[op];\n return `https://x.com/i/api/graphql/${queryId}/${operationName}`;\n}\n\ntype Vars = Record<string, unknown>;\ntype Feats = Record<string, boolean>;\n\nexport interface BuiltRequest {\n variables: Vars;\n features: Feats;\n fieldToggles?: Vars;\n}\n\n/** A built request that also names the op it targets (for url resolution). */\ninterface OpRequest extends BuiltRequest {\n op: OpName;\n}\n\ninterface Overrides {\n /** Extra/override variables merged on top of the builder defaults. */\n kv?: Vars;\n /** Override feature flags merged on top of FEATURES (+ any builder extras). */\n ft?: Feats;\n}\n\nfunction withCursor(base: Vars, cursor?: string): Vars {\n return cursor === undefined ? base : { ...base, cursor };\n}\n\n// --- SearchTimeline ---------------------------------------------------------\n\nexport type SearchProduct = 'Top' | 'Latest' | 'Media' | 'People';\n\nexport interface SearchParams extends Overrides {\n query: string;\n count?: number;\n product?: SearchProduct;\n cursor?: string;\n}\n\nexport function searchRequest(params: SearchParams): BuiltRequest {\n const { query, count = 20, product = 'Latest', cursor, kv, ft } = params;\n const variables: Vars = withCursor(\n { rawQuery: query, count, querySource: 'typed_query', product },\n cursor,\n );\n return {\n variables: { ...variables, ...kv },\n features: { ...FEATURES, ...ft },\n fieldToggles: { withArticleRichContentState: false },\n };\n}\n\n// --- Bookmarks --------------------------------------------------------------\n\nexport interface BookmarksParams extends Overrides {\n count?: number;\n cursor?: string;\n}\n\nexport function bookmarksRequest(params: BookmarksParams): BuiltRequest {\n const { count = 20, cursor, kv, ft } = params;\n const variables = withCursor({ count, includePromotedContent: true }, cursor);\n return {\n variables: { ...variables, ...kv },\n features: { ...FEATURES, graphql_timeline_v2_bookmark_timeline: true, ...ft },\n };\n}\n\n// --- UserTweets / UserTweetsAndReplies --------------------------------------\n\nexport interface UserTweetsParams extends Overrides {\n userId: string;\n count?: number;\n cursor?: string;\n replies?: boolean;\n}\n\nexport function userTweetsRequest(params: UserTweetsParams): OpRequest {\n const { userId, count = 40, cursor, replies = false, kv, ft } = params;\n const op: OpName = replies ? 'UserTweetsAndReplies' : 'UserTweets';\n const variables = withCursor(\n {\n userId,\n count,\n includePromotedContent: false,\n withQuickPromoteEligibilityTweetFields: true,\n withVoice: true,\n withV2Timeline: true,\n },\n cursor,\n );\n return {\n op,\n variables: { ...variables, ...kv },\n features: { ...FEATURES, ...ft },\n fieldToggles: { withArticlePlainText: false },\n };\n}\n\n// --- UserByScreenName -------------------------------------------------------\n\nexport interface UserByScreenNameParams extends Overrides {\n screenName: string;\n}\n\nexport function userByScreenNameRequest(params: UserByScreenNameParams): BuiltRequest {\n const { screenName, kv, ft } = params;\n return {\n variables: { screen_name: screenName, withGrokTranslatedBio: false, ...kv },\n features: { ...FEATURES, ...ft },\n fieldToggles: { withPayments: false, withAuxiliaryUserLabels: true },\n };\n}\n\n// --- TweetDetail ------------------------------------------------------------\n\nexport interface TweetDetailParams extends Overrides {\n focalTweetId: string;\n cursor?: string;\n}\n\nexport function tweetDetailRequest(params: TweetDetailParams): BuiltRequest {\n const { focalTweetId, cursor, kv, ft } = params;\n const variables = withCursor(\n {\n focalTweetId,\n with_rux_injections: false,\n rankingMode: 'Relevance',\n includePromotedContent: true,\n withCommunity: true,\n withQuickPromoteEligibilityTweetFields: true,\n withBirdwatchNotes: true,\n withVoice: true,\n },\n cursor,\n );\n return {\n variables: { ...variables, ...kv },\n features: { ...FEATURES, ...ft },\n fieldToggles: { withArticleRichContentState: false, withArticlePlainText: false },\n };\n}\n\n// --- Param encoding ---------------------------------------------------------\n\n/** Stable JSON.stringify with sorted keys (deterministic param output). */\nfunction stableStringify(value: unknown): string {\n if (Array.isArray(value)) {\n return `[${value.map(stableStringify).join(',')}]`;\n }\n if (value !== null && typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const body = keys.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`).join(',');\n return `{${body}}`;\n }\n return JSON.stringify(value) ?? 'null';\n}\n\n/**\n * Encode a request into a deterministic query string (no leading `?`). Each of\n * variables / features / fieldToggles is JSON-stringified into a single param with a\n * stable (sorted) key order so identical input always yields identical output.\n */\nexport function encodeParams(req: {\n variables: object;\n features: object;\n fieldToggles?: object;\n}): string {\n const params = new URLSearchParams();\n params.set('variables', stableStringify(req.variables));\n params.set('features', stableStringify(req.features));\n if (req.fieldToggles !== undefined) {\n params.set('fieldToggles', stableStringify(req.fieldToggles));\n }\n return params.toString();\n}\n","// The GraphQL request driver: pure transport + X/Twitter's resilience policy\n// (rate-limit backoff, stale-transaction-id retry, feature-drift detection). It\n// returns RAW json — the engine layer parses it. See docs/ENGINE-RESEARCH.md §4.\n//\n// The driver never imports the x-client-transaction-id generator directly: the\n// txid arrives through an injected TransactionProvider, so it stays testable and\n// the regeneration-on-404 path is exercisable with a counter.\n\nimport type { Cookies } from './auth.ts';\nimport { buildHeaders } from './auth.ts';\nimport type { BuiltRequest, OpName } from './ops.ts';\nimport { encodeParams, graphqlUrl } from './ops.ts';\n\n/** Yields the x-client-transaction-id for a request (method + path bound). */\nexport type TransactionProvider = (method: string, path: string) => Promise<string>;\n\nexport type ClientResult =\n | { ok: true; value: unknown }\n | { ok: false; error: { code: string; message: string; status?: number } };\n\ninterface CreateClientArgs {\n cookies: Cookies;\n transaction: TransactionProvider;\n fetchImpl?: typeof fetch;\n sleep?: (ms: number) => Promise<void>;\n maxRetries?: number;\n clientLanguage?: string;\n}\n\n// When X gives no reset header, wait a modest fixed window before retrying.\nconst DEFAULT_BACKOFF_MS = 1000;\n\nconst defaultSleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n/** Does a parsed body carry X's `(336) features cannot be null` feature-drift signal? */\nfunction isFeatureDrift(body: unknown): boolean {\n if (body === null || typeof body !== 'object') return false;\n const errors = (body as { errors?: unknown }).errors;\n if (!Array.isArray(errors)) return false;\n return errors.some((err) => {\n if (err === null || typeof err !== 'object') return false;\n const code = (err as { code?: unknown }).code;\n const message = (err as { message?: unknown }).message;\n if (code === 336) return true;\n return typeof message === 'string' && /features cannot be null/i.test(message);\n });\n}\n\nfunction featureDrift(op: OpName): ClientResult {\n return {\n ok: false,\n error: {\n code: 'FEATURE_DRIFT',\n message: `Feature drift on ${op}: X rejected the features blob — refresh src/engine/ops.ts features/query-ids.`,\n },\n };\n}\n\nasync function safeJson(res: Response): Promise<unknown> {\n try {\n return await res.json();\n } catch {\n return null;\n }\n}\n\n/** ms to wait before a 429 retry: until the reset header, else a fixed backoff. */\nfunction backoffMs(res: Response): number {\n const resetHeader = res.headers.get('x-rate-limit-reset');\n const reset = resetHeader === null ? null : Number(resetHeader);\n if (reset === null || !Number.isFinite(reset)) return DEFAULT_BACKOFF_MS;\n const until = reset * 1000 - Date.now();\n return until > 0 ? until : DEFAULT_BACKOFF_MS;\n}\n\n// A retry directive: sleep `waitMs` (0 = none) then re-issue the request.\ntype Retry = { retry: true; waitMs: number };\nconst RETRY_NOW: Retry = { retry: true, waitMs: 0 };\n\nfunction isRetry(value: ClientResult | Retry): value is Retry {\n return 'retry' in value;\n}\n\n/** Map a non-retryable status to its terminal error result. */\nfunction terminalError(op: OpName, status: number, body: unknown): ClientResult {\n if (status === 400) {\n if (isFeatureDrift(body)) return featureDrift(op);\n return { ok: false, error: { code: 'BAD_REQUEST', status: 400, message: 'Bad request.' } };\n }\n if (status === 401 || status === 403) {\n return {\n ok: false,\n error: {\n code: 'AUTH_FAILED',\n status,\n message: 'Auth failed — session cookies expired or invalid.',\n },\n };\n }\n return {\n ok: false,\n error: { code: 'FETCH_FAILED', status, message: `Request failed with status ${status}.` },\n };\n}\n\nexport function createClient(args: CreateClientArgs): {\n get(op: OpName, request: BuiltRequest): Promise<ClientResult>;\n} {\n const {\n cookies,\n transaction,\n fetchImpl = fetch,\n sleep = defaultSleep,\n maxRetries = 3,\n clientLanguage,\n } = args;\n\n async function fetchOnce(op: OpName, request: BuiltRequest): Promise<Response> {\n const url = `${graphqlUrl(op)}?${encodeParams(request)}`;\n const path = new URL(url).pathname;\n const txid = await transaction('GET', path);\n const headers = buildHeaders({ cookies, transactionId: txid, clientLanguage });\n return fetchImpl(url, { method: 'GET', headers });\n }\n\n // Classify one response into either a terminal result or a retry directive,\n // tracking the per-status retry budgets through the mutable `retries` counters.\n async function classify(\n op: OpName,\n res: Response,\n retries: { rateLimit: number; notFound: number },\n ): Promise<ClientResult | Retry> {\n const { status } = res;\n\n if (status === 200) {\n const body = await safeJson(res);\n return isFeatureDrift(body) ? featureDrift(op) : { ok: true, value: body };\n }\n\n if (status === 429) {\n if (retries.rateLimit >= maxRetries) {\n return {\n ok: false,\n error: { code: 'RATE_LIMITED', status: 429, message: 'Rate limited; retries exhausted.' },\n };\n }\n retries.rateLimit += 1;\n return { retry: true, waitMs: backoffMs(res) };\n }\n\n if (status === 404) {\n // X 404s a stale transaction-id; regenerate (the next fetch calls\n // transaction again for a fresh txid) and retry.\n if (retries.notFound >= maxRetries) {\n return {\n ok: false,\n error: {\n code: 'NOT_FOUND',\n status: 404,\n message: 'Not found; retries exhausted (stale txid?).',\n },\n };\n }\n retries.notFound += 1;\n return RETRY_NOW;\n }\n\n // 400 needs the body for feature-drift detection; other terminals don't.\n const body = status === 400 ? await safeJson(res) : null;\n return terminalError(op, status, body);\n }\n\n async function get(op: OpName, request: BuiltRequest): Promise<ClientResult> {\n const retries = { rateLimit: 0, notFound: 0 };\n\n for (;;) {\n let res: Response;\n try {\n res = await fetchOnce(op, request);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return { ok: false, error: { code: 'FETCH_FAILED', message } };\n }\n\n const outcome = await classify(op, res, retries);\n if (!isRetry(outcome)) return outcome;\n if (outcome.waitMs > 0) await sleep(outcome.waitMs);\n }\n }\n\n return { get };\n}\n","// Automatic browser-cookie extraction for X — no manual export.\n// macOS: reads each Chromium browser's Cookies DB (via the system `sqlite3`)\n// and decrypts the values with the AES key from the login Keychain\n// (\"<Browser> Safe Storage\"), mirroring browser-cookie3 / twitter-cli. The\n// first browser+profile logged into x.com wins. Falls back to XRELAY_COOKIES.\nimport { execFileSync } from 'node:child_process';\nimport { createDecipheriv, pbkdf2Sync } from 'node:crypto';\nimport { copyFileSync, existsSync, mkdtempSync, readdirSync } from 'node:fs';\nimport { homedir, tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { type Cookies, parseCookies } from './auth.ts';\n\n// --- pure crypto ------------------------------------------------------------\n\n/** Chrome/Chromium macOS key derivation: PBKDF2(secret, 'saltysalt', 1003, 16, sha1). */\nexport function deriveKey(keychainSecret: string): Buffer {\n return pbkdf2Sync(keychainSecret, 'saltysalt', 1003, 16, 'sha1');\n}\n\nfunction isPrintableAscii(s: string): boolean {\n return /^[\\x20-\\x7e]*$/.test(s);\n}\n\n/**\n * Decrypts a Chromium cookie value. `v10`/`v11` values are AES-128-CBC\n * (iv = 16 spaces) over the Keychain-derived key; newer Chrome prepends a\n * 32-byte SHA-256(domain) to the plaintext, which we strip. Unencrypted values\n * pass through.\n */\nexport function decryptCookieValue(encrypted: Buffer, key: Buffer): string | null {\n if (encrypted.length === 0) return '';\n const prefix = encrypted.subarray(0, 3).toString('latin1');\n if (prefix !== 'v10' && prefix !== 'v11') return encrypted.toString('utf8');\n\n const iv = Buffer.alloc(16, ' ');\n const decipher = createDecipheriv('aes-128-cbc', key, iv);\n decipher.setAutoPadding(false);\n let out: Buffer;\n try {\n out = Buffer.concat([decipher.update(encrypted.subarray(3)), decipher.final()]);\n } catch {\n return null;\n }\n\n // Strip PKCS7 padding manually (Chrome's padding isn't always block-standard).\n const pad = out[out.length - 1] ?? 0;\n if (pad > 0 && pad <= 16) out = out.subarray(0, out.length - pad);\n\n const direct = out.toString('utf8');\n if (isPrintableAscii(direct)) return direct;\n const stripped = out.subarray(32).toString('utf8');\n if (isPrintableAscii(stripped)) return stripped;\n return direct;\n}\n\nexport interface CookieRow {\n hostKey: string;\n name: string;\n value: string;\n}\n\n/** From decrypted X cookie rows, build the Cookies (auth_token + ct0 + all others). */\nexport function pickAuthCookies(rows: CookieRow[]): Cookies | null {\n let authToken: string | undefined;\n let ct0: string | undefined;\n const extra: Record<string, string> = {};\n for (const row of rows) {\n if (!row.name || !row.value) continue;\n if (row.name === 'auth_token') authToken = row.value;\n else if (row.name === 'ct0') ct0 = row.value;\n else extra[row.name] = row.value;\n }\n if (authToken === undefined || ct0 === undefined) return null;\n const cookies: Cookies = { authToken, ct0 };\n if (Object.keys(extra).length > 0) cookies.extra = extra;\n return cookies;\n}\n\n// --- macOS integration ------------------------------------------------------\n\ninterface Browser {\n name: string;\n /** Keychain service: \"<keychain> Safe Storage\". */\n keychain: string;\n /** Dir under ~/Library/Application Support. */\n base: string;\n}\n\nconst BROWSERS: Browser[] = [\n { name: 'arc', keychain: 'Arc', base: 'Arc/User Data' },\n { name: 'chrome', keychain: 'Chrome', base: 'Google/Chrome' },\n { name: 'brave', keychain: 'Brave', base: 'BraveSoftware/Brave-Browser' },\n { name: 'edge', keychain: 'Microsoft Edge', base: 'Microsoft Edge' },\n];\n\nfunction browserOrder(): Browser[] {\n const pref = (process.env.XRELAY_BROWSER ?? '').trim().toLowerCase();\n if (!pref) return BROWSERS;\n const first = BROWSERS.filter((b) => b.name === pref);\n return first.length ? [...first, ...BROWSERS.filter((b) => b.name !== pref)] : BROWSERS;\n}\n\n/** The AES storage secret from the login Keychain (triggers a one-time auth prompt). */\nfunction keychainSecret(browser: Browser): string | null {\n try {\n return execFileSync(\n 'security',\n ['find-generic-password', '-w', '-s', `${browser.keychain} Safe Storage`],\n { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] },\n ).trim();\n } catch {\n return null;\n }\n}\n\nfunction profileCookieDbs(browser: Browser): string[] {\n const root = join(homedir(), 'Library', 'Application Support', browser.base);\n if (!existsSync(root)) return [];\n const dbs: string[] = [];\n const defaultDb = join(root, 'Default', 'Cookies');\n if (existsSync(defaultDb)) dbs.push(defaultDb);\n for (const entry of readdirSync(root)) {\n if (entry.startsWith('Profile ')) {\n const db = join(root, entry, 'Cookies');\n if (existsSync(db)) dbs.push(db);\n }\n }\n return dbs;\n}\n\n/** Read X cookie rows from a Cookies DB via the system sqlite3 (on a temp copy). */\nfunction readCookieRows(dbPath: string): { hostKey: string; name: string; hexValue: string }[] {\n const tmp = join(mkdtempSync(join(tmpdir(), 'xrelay-')), 'Cookies');\n copyFileSync(dbPath, tmp);\n for (const suffix of ['-wal', '-shm']) {\n if (existsSync(dbPath + suffix)) copyFileSync(dbPath + suffix, tmp + suffix);\n }\n const sql =\n 'SELECT host_key AS hostKey, name, hex(encrypted_value) AS hexValue FROM cookies ' +\n \"WHERE host_key LIKE '%x.com' OR host_key LIKE '%twitter.com'\";\n try {\n const out = execFileSync('sqlite3', ['-readonly', '-json', tmp, sql], {\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'ignore'],\n }).trim();\n if (!out) return [];\n return JSON.parse(out) as { hostKey: string; name: string; hexValue: string }[];\n } catch {\n return [];\n }\n}\n\n/** Auto-extract X cookies from the local browser. Returns null if none found. */\nexport function extractCookies(): Cookies | null {\n if (process.platform !== 'darwin') return null;\n for (const browser of browserOrder()) {\n const dbs = profileCookieDbs(browser);\n if (dbs.length === 0) continue;\n const secret = keychainSecret(browser);\n if (!secret) continue;\n const key = deriveKey(secret);\n for (const db of dbs) {\n const rows = readCookieRows(db).map((r) => ({\n hostKey: r.hostKey,\n name: r.name,\n value: decryptCookieValue(Buffer.from(r.hexValue, 'hex'), key) ?? '',\n }));\n const cookies = pickAuthCookies(rows);\n if (cookies) return cookies;\n }\n }\n return null;\n}\n\n/** Cookies resolution: XRELAY_COOKIES env → automatic browser extraction. */\nexport function getCookies(): Cookies {\n const env = process.env.XRELAY_COOKIES;\n if (env) return parseCookies(env);\n const cookies = extractCookies();\n if (cookies) return cookies;\n throw new Error(\n 'No X cookies found. Log into x.com in Arc/Chrome/Brave/Edge (macOS), or set ' +\n 'XRELAY_COOKIES=\"auth_token=...; ct0=...\". If a Keychain prompt appeared, click \"Always Allow\".',\n );\n}\n","// Normalize X/Twitter's private GraphQL JSON into our clean domain types, plus\n// cursor / end-detection for timelines. Pure — no I/O, no network. The engine's\n// client.ts feeds raw JSON in; everything downstream consumes our domain types.\n// Source of truth: docs/ENGINE-RESEARCH.md §5 (dual core/legacy, field map,\n// pagination/end-detection) and §2 (timeline shape).\n\nimport type {\n Author,\n MediaKind,\n Metrics,\n ThreadResult,\n Tweet,\n TweetPage,\n UserProfile,\n} from '../types.ts';\n\n// ── Narrowing helpers ───────────────────────────────────────────────────────\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/** A child object by key, or undefined when absent / not an object. */\nfunction child(node: Record<string, unknown>, key: string): Record<string, unknown> | undefined {\n const value = node[key];\n return isRecord(value) ? value : undefined;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\n/** Coerce a number or a numeric string (\"1234\") to a number, else undefined. */\nfunction asNumber(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string' && value.trim() !== '') {\n const parsed = Number(value);\n if (Number.isFinite(parsed)) return parsed;\n }\n return undefined;\n}\n\nfunction asBool(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined;\n}\n\n/**\n * Recursive deep search collecting every value stored under `key` anywhere in a\n * nested object/array tree (port of twikit's `find_dict`). Lets the parser stay\n * robust to X's layout drift instead of hardcoding full JSON paths.\n *\n * @param findFirst when true, stop and return after the first match.\n */\nexport function findDict(obj: unknown, key: string, findFirst = false): unknown[] {\n const out: unknown[] = [];\n\n // Returns true once `findFirst` is satisfied, to unwind the recursion early.\n const walk = (node: unknown): boolean => {\n if (Array.isArray(node)) {\n return node.some(walk);\n }\n if (!isRecord(node)) return false;\n for (const [k, value] of Object.entries(node)) {\n if (k === key) {\n out.push(value);\n if (findFirst) return true;\n }\n if (walk(value)) return true;\n }\n return false;\n };\n\n walk(obj);\n return out;\n}\n\n// ── User normalization ──────────────────────────────────────────────────────\n\n/**\n * Normalize a `user_results.result` node into a UserProfile. Reads the new\n * sub-object locations (`core`, `avatar`, `verification`, `profile_bio`,\n * `location`) with a `legacy` fallback so it works whether X populated `legacy`\n * or hoisted the fields out (docs/ENGINE-RESEARCH.md §5). Returns null for any\n * node that isn't a real user (e.g. `UserUnavailable`).\n */\nexport function parseUserResult(result: unknown): UserProfile | null {\n if (!isRecord(result)) return null;\n if (result.__typename !== undefined && result.__typename !== 'User') return null;\n\n const legacy = child(result, 'legacy');\n const core = child(result, 'core');\n\n const handle = asString(core?.screen_name) ?? asString(legacy?.screen_name);\n const id = asString(result.rest_id) ?? asString(legacy?.id_str);\n if (handle === undefined || id === undefined) return null;\n\n const name = asString(core?.name) ?? asString(legacy?.name) ?? handle;\n // Verification is the logical-OR of three independent signals (blue check,\n // the new `verification` block, legacy.verified) — any one true means verified.\n const verification = child(result, 'verification');\n const verified =\n asBool(result.is_blue_verified) === true ||\n asBool(verification?.verified) === true ||\n asBool(legacy?.verified) === true;\n\n const followers = asNumber(legacy?.followers_count) ?? asNumber(result.followers_count) ?? 0;\n const following = asNumber(legacy?.friends_count) ?? asNumber(result.friends_count) ?? 0;\n const tweets = asNumber(legacy?.statuses_count) ?? asNumber(result.statuses_count) ?? 0;\n\n const profile: UserProfile = {\n id,\n handle,\n name,\n verified,\n followers,\n following,\n tweets,\n url: `https://x.com/${handle}`,\n };\n applyUserOptionals(profile, result, legacy, core);\n return profile;\n}\n\n/** Populate bio/createdAt/location/avatar on a profile in place (sub-object then legacy). */\nfunction applyUserOptionals(\n profile: UserProfile,\n result: Record<string, unknown>,\n legacy: Record<string, unknown> | undefined,\n core: Record<string, unknown> | undefined,\n): void {\n const profileBio = child(result, 'profile_bio');\n const bio = asString(legacy?.description) ?? asString(profileBio?.description);\n if (bio !== undefined) profile.bio = bio;\n\n const createdAt = asString(core?.created_at) ?? asString(legacy?.created_at);\n if (createdAt !== undefined) profile.createdAt = createdAt;\n\n const locationObj = child(result, 'location');\n const location = asString(legacy?.location) ?? asString(locationObj?.location);\n if (location !== undefined) profile.location = location;\n\n const avatarObj = child(result, 'avatar');\n const avatar = asString(legacy?.profile_image_url_https) ?? asString(avatarObj?.image_url);\n if (avatar !== undefined) profile.avatar = avatar;\n}\n\n// ── Tweet normalization ─────────────────────────────────────────────────────\n\n/** A UserProfile reduced to the embedded-author shape. */\nfunction authorFromProfile(profile: UserProfile): Author {\n const author: Author = {\n id: profile.id,\n handle: profile.handle,\n name: profile.name,\n verified: profile.verified,\n followers: profile.followers,\n };\n if (profile.avatar !== undefined) author.avatar = profile.avatar;\n return author;\n}\n\n/** Pull a normalized author out of `result.core.user_results.result`. */\nfunction parseAuthor(result: Record<string, unknown>): Author | null {\n const core = child(result, 'core');\n const userResults = core ? child(core, 'user_results') : undefined;\n const userNode = userResults ? userResults.result : undefined;\n const profile = parseUserResult(userNode);\n return profile ? authorFromProfile(profile) : null;\n}\n\n/** Long-form body from note_tweet, else legacy/hoisted full_text. */\nfunction tweetText(result: Record<string, unknown>, legacy: Record<string, unknown> | undefined) {\n const note = child(result, 'note_tweet');\n const noteResults = note ? child(note, 'note_tweet_results') : undefined;\n const noteResult = noteResults ? child(noteResults, 'result') : undefined;\n const noteText = noteResult ? asString(noteResult.text) : undefined;\n if (noteText !== undefined) return noteText;\n return asString(legacy?.full_text) ?? asString(result.full_text) ?? '';\n}\n\n/** Views live OUTSIDE legacy on the result root (views.count), with ext_views fallback. */\nfunction tweetViews(\n result: Record<string, unknown>,\n legacy: Record<string, unknown> | undefined,\n): number | undefined {\n const views = child(result, 'views') ?? child(result, 'ext_views');\n const extFromLegacy = legacy ? child(legacy, 'ext_views') : undefined;\n return asNumber(views?.count) ?? asNumber(extFromLegacy?.count);\n}\n\nfunction tweetMetrics(\n result: Record<string, unknown>,\n legacy: Record<string, unknown> | undefined,\n): Metrics {\n const pick = (key: string) => asNumber(legacy?.[key]) ?? asNumber(result[key]);\n const metrics: Metrics = {};\n const likes = pick('favorite_count');\n const retweets = pick('retweet_count');\n const replies = pick('reply_count');\n const quotes = pick('quote_count');\n const bookmarks = pick('bookmark_count');\n const views = tweetViews(result, legacy);\n if (likes !== undefined) metrics.likes = likes;\n if (retweets !== undefined) metrics.retweets = retweets;\n if (replies !== undefined) metrics.replies = replies;\n if (quotes !== undefined) metrics.quotes = quotes;\n if (bookmarks !== undefined) metrics.bookmarks = bookmarks;\n if (views !== undefined) metrics.views = views;\n return metrics;\n}\n\n/** Collect `field` strings from entities[arrayKey][].`field`. */\nfunction entityStrings(\n entities: Record<string, unknown> | undefined,\n arrayKey: string,\n field: string,\n) {\n const arr = entities?.[arrayKey];\n if (!Array.isArray(arr)) return undefined;\n const out: string[] = [];\n for (const item of arr) {\n if (isRecord(item)) {\n const value = asString(item[field]);\n if (value !== undefined) out.push(value);\n }\n }\n return out.length > 0 ? out : undefined;\n}\n\nconst MEDIA_MAP: Record<string, MediaKind> = {\n photo: 'photo',\n video: 'video',\n animated_gif: 'gif',\n};\n\nfunction tweetMedia(extended: Record<string, unknown> | undefined): MediaKind[] | undefined {\n const arr = extended?.media;\n if (!Array.isArray(arr)) return undefined;\n const out: MediaKind[] = [];\n for (const item of arr) {\n if (isRecord(item)) {\n const kind = asString(item.type);\n if (kind !== undefined && kind in MEDIA_MAP) {\n const mapped = MEDIA_MAP[kind];\n if (mapped !== undefined) out.push(mapped);\n }\n }\n }\n return out.length > 0 ? out : undefined;\n}\n\n/** Read a `node.legacy?.X ?? node.X` field as a string (works hoisted or legacy). */\nfunction dualString(\n result: Record<string, unknown>,\n legacy: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n return asString(legacy?.[key]) ?? asString(result[key]);\n}\n\n/** Populate the optional scalar + entity/media fields on a tweet in place. */\nfunction applyTweetDetails(\n tweet: Tweet,\n result: Record<string, unknown>,\n legacy: Record<string, unknown> | undefined,\n): void {\n const lang = dualString(result, legacy, 'lang');\n if (lang !== undefined) tweet.lang = lang;\n const createdAt = dualString(result, legacy, 'created_at');\n if (createdAt !== undefined) tweet.createdAt = createdAt;\n const conversationId = dualString(result, legacy, 'conversation_id_str');\n if (conversationId !== undefined) tweet.conversationId = conversationId;\n\n const entities = child(result, 'entities') ?? (legacy ? child(legacy, 'entities') : undefined);\n const extended =\n child(result, 'extended_entities') ?? (legacy ? child(legacy, 'extended_entities') : undefined);\n\n const hashtags = entityStrings(entities, 'hashtags', 'text');\n if (hashtags !== undefined) tweet.hashtags = hashtags;\n const mentions = entityStrings(entities, 'user_mentions', 'screen_name');\n if (mentions !== undefined) tweet.mentions = mentions;\n const urls = entityStrings(entities, 'urls', 'expanded_url');\n if (urls !== undefined) tweet.urls = urls;\n const media = tweetMedia(extended);\n if (media !== undefined) tweet.media = media;\n}\n\n/** Populate isReply/isRetweet/isQuote + the quoted-tweet recursion in place. */\nfunction applyTweetRelations(\n tweet: Tweet,\n result: Record<string, unknown>,\n legacy: Record<string, unknown> | undefined,\n): void {\n if (dualString(result, legacy, 'in_reply_to_status_id_str') !== undefined) tweet.isReply = true;\n\n const isRetweet =\n child(result, 'retweeted_status_result') !== undefined ||\n (legacy ? child(legacy, 'retweeted_status_result') !== undefined : false);\n if (isRetweet) tweet.isRetweet = true;\n\n const quoteId = dualString(result, legacy, 'quoted_status_id_str');\n const quotedNode =\n child(result, 'quoted_status_result') ??\n (legacy ? child(legacy, 'quoted_status_result') : undefined);\n if (quoteId !== undefined || quotedNode !== undefined) tweet.isQuote = true;\n if (quotedNode !== undefined) {\n const quoted = parseTweetResult(quotedNode.result);\n if (quoted !== null) tweet.quoted = quoted;\n }\n}\n\n/**\n * Normalize a `tweet_results.result` node into a Tweet. Unwraps\n * `TweetWithVisibilityResults` (→ `.tweet`), returns null for a `TweetTombstone`\n * (or any non-tweet). Reads every legacy field as `node.legacy?.X ?? node.X` so\n * it works whether legacy is populated or hoisted (docs/ENGINE-RESEARCH.md §5).\n */\nexport function parseTweetResult(result: unknown): Tweet | null {\n if (!isRecord(result)) return null;\n\n if (result.__typename === 'TweetWithVisibilityResults') {\n return parseTweetResult(result.tweet);\n }\n if (result.__typename === 'TweetTombstone') return null;\n\n const legacy = child(result, 'legacy');\n const id = asString(result.rest_id) ?? asString(legacy?.id_str);\n if (id === undefined) return null;\n\n const author = parseAuthor(result);\n if (author === null) return null;\n\n const tweet: Tweet = {\n id,\n url: `https://x.com/${author.handle}/status/${id}`,\n text: tweetText(result, legacy),\n author,\n metrics: tweetMetrics(result, legacy),\n };\n\n applyTweetDetails(tweet, result, legacy);\n applyTweetRelations(tweet, result, legacy);\n return tweet;\n}\n\n// ── Timeline / pagination ───────────────────────────────────────────────────\n\n// Entry-id prefixes that carry tweets we want.\nconst TWEET_ENTRY_PREFIXES = ['tweet', 'search-grid', 'profile-conversation'];\n// Entry-id prefixes we always drop (cursors, ads, recommendations, modules-as-noise).\nconst DROP_ENTRY_PREFIXES = ['cursor-', 'promoted', 'who-to-follow', 'module-'];\n\nfunction startsWithAny(value: string, prefixes: string[]): boolean {\n return prefixes.some((prefix) => value.startsWith(prefix));\n}\n\n/** Locate the first `instructions` array anywhere in the response (layout-drift safe). */\nfunction locateInstructions(json: unknown): unknown[] {\n const found = findDict(json, 'instructions', true)[0];\n return Array.isArray(found) ? found : [];\n}\n\n/** Flatten every instruction's `entries` into one ordered list. */\nfunction collectEntries(instructions: unknown[]): Record<string, unknown>[] {\n const entries: Record<string, unknown>[] = [];\n for (const instruction of instructions) {\n if (isRecord(instruction) && Array.isArray(instruction.entries)) {\n for (const entry of instruction.entries) {\n if (isRecord(entry)) entries.push(entry);\n }\n }\n }\n return entries;\n}\n\n/** The cursor value from a Bottom-cursor entry, else undefined. */\nfunction entryBottomCursor(entry: Record<string, unknown>, entryId: string): string | undefined {\n const content = child(entry, 'content');\n const itemContent = content ? child(content, 'itemContent') : undefined;\n const cursorType = asString(content?.cursorType) ?? asString(itemContent?.cursorType);\n const isBottom =\n cursorType === 'Bottom' ||\n cursorType === 'ShowMoreThreads' ||\n entryId.startsWith('cursor-bottom') ||\n entryId.startsWith('cursor-showmore');\n if (!isBottom) return undefined;\n return asString(content?.value) ?? asString(itemContent?.value);\n}\n\n/** Every `tweet_results.result` node reachable under an entry (item or module items[]). */\nfunction entryTweetNodes(entry: Record<string, unknown>): unknown[] {\n return findDict(entry, 'tweet_results').map((node) => (isRecord(node) ? node.result : undefined));\n}\n\n/**\n * Walk a timeline response into a TweetPage. Collects tweets from tweet/\n * search-grid/profile-conversation entries (including module `items[]`), sets\n * nextCursor from the Bottom cursor entry, drops cursor/promoted/who-to-follow/\n * module entries, de-dupes by id, and skips any tweet that fails to parse so one\n * bad node never kills the page (docs/ENGINE-RESEARCH.md §5).\n */\nexport function parseTimeline(json: unknown, _opts?: { instructionsPath?: string }): TweetPage {\n const entries = collectEntries(locateInstructions(json));\n const tweets: Tweet[] = [];\n const seen = new Set<string>();\n let nextCursor: string | undefined;\n\n for (const entry of entries) {\n const entryId = asString(entry.entryId) ?? '';\n\n const cursor = entryBottomCursor(entry, entryId);\n if (cursor !== undefined) nextCursor = cursor;\n\n if (startsWithAny(entryId, DROP_ENTRY_PREFIXES)) continue;\n if (!startsWithAny(entryId, TWEET_ENTRY_PREFIXES)) continue;\n\n for (const node of entryTweetNodes(entry)) {\n try {\n const tweet = parseTweetResult(node);\n if (tweet !== null && !seen.has(tweet.id)) {\n seen.add(tweet.id);\n tweets.push(tweet);\n }\n } catch {\n // One bad tweet never kills the page.\n }\n }\n }\n\n const page: TweetPage = { tweets };\n if (nextCursor !== undefined) page.nextCursor = nextCursor;\n return page;\n}\n\n/**\n * Parse a TweetDetail response into a ThreadResult: the tweet matching\n * focalTweetId is the root, the rest are replies, in entry order. Carries the\n * Bottom / ShowMoreThreads cursor as nextCursor.\n */\nexport function parseThread(json: unknown, focalTweetId: string): ThreadResult {\n const page = parseTimeline(json);\n const root = page.tweets.find((tweet) => tweet.id === focalTweetId);\n const replies = page.tweets.filter((tweet) => tweet.id !== focalTweetId);\n\n const result: ThreadResult = {\n root: root ?? {\n id: focalTweetId,\n url: `https://x.com/i/status/${focalTweetId}`,\n text: '',\n author: { id: '', handle: '', name: '', verified: false },\n metrics: {},\n },\n replies,\n };\n if (page.nextCursor !== undefined) result.nextCursor = page.nextCursor;\n return result;\n}\n","// x-client-transaction-id generator. Vendored + ported from\n// Lqm1/x-client-transaction-id (MIT), adapted to Node: @std/encoding -> Buffer,\n// crypto.subtle -> node:crypto. The byte-assembly is extracted into the pure\n// `assembleTransactionId` so it can be unit-tested deterministically.\n// Algorithm + constants: docs/ENGINE-RESEARCH.md §3.\nimport { createHash } from 'node:crypto';\nimport Cubic from './cubic.ts';\nimport type { XDocument, XElement } from './dom.ts';\nimport {\n AnimationFrameDataError,\n ClientTransactionNotInitializedError,\n IndicesNotInitializedError,\n KeyByteIndicesExtractionError,\n OnDemandFileFetchError,\n OnDemandFileUrlResolutionError,\n SiteVerificationKeyNotFoundError,\n} from './errors.ts';\nimport { interpolate } from './interpolate.ts';\nimport { convertRotationToMatrix } from './rotation.ts';\nimport { floatToHex, isOdd } from './utils.ts';\n\nconst ON_DEMAND_CHUNK_NAME = 'ondemand.s';\nconst INDICES_REGEX = /\\(\\w\\[(\\d{1,2})\\],\\s*16\\)/g;\nconst ON_DEMAND_FILE_HASH_REGEX =\n /(\\d+):\\s*[\"']ondemand\\.s[\"'][\\s\\S]*?\\}\\)\\[e\\]\\s*\\|\\|\\s*e\\)\\s*\\+\\s*[\"']\\.[\"']\\s*\\+\\s*\\(\\{[\\s\\S]*?\\b\\1:\\s*[\"']([a-zA-Z0-9_-]+)[\"']/s;\n\nconst DEFAULT_KEYWORD = 'obfiowerehiring';\nconst ADDITIONAL_RANDOM_NUMBER = 3;\n/** X's custom epoch (seconds) subtracted from Unix time. Stable since 2023. */\nconst EPOCH_SECONDS = 1682924400;\n\nfunction resolveOnDemandFileUrlFromRuntime(runtimeSource: string): string | null {\n const match = ON_DEMAND_FILE_HASH_REGEX.exec(runtimeSource);\n if (!match) return null;\n return `https://abs.twimg.com/responsive-web/client-web/${ON_DEMAND_CHUNK_NAME}.${match[2]}a.js`;\n}\n\n/**\n * Pure byte-assembly of a transaction id: SHA-256 of the data string, then\n * `[rnd, ...([keyBytes | timeBytes(LE) | hash[0:16] | 3] XOR rnd)]` base64'd\n * without padding. `randomNum` is injectable so the assembly is testable.\n */\nexport async function assembleTransactionId(\n keyBytes: number[],\n animationKey: string,\n method: string,\n path: string,\n timeNow: number,\n randomNum?: number,\n): Promise<string> {\n const timeNowBytes = [\n timeNow & 0xff,\n (timeNow >> 8) & 0xff,\n (timeNow >> 16) & 0xff,\n (timeNow >> 24) & 0xff,\n ];\n\n const data = `${method}!${path}!${timeNow}${DEFAULT_KEYWORD}${animationKey}`;\n const hashBytes = [...createHash('sha256').update(data, 'utf8').digest()];\n\n const rnd = randomNum ?? Math.floor(Math.random() * 256);\n const bytesArr = [\n ...keyBytes,\n ...timeNowBytes,\n ...hashBytes.slice(0, 16),\n ADDITIONAL_RANDOM_NUMBER,\n ];\n const out = Uint8Array.from([rnd, ...bytesArr.map((b) => b ^ rnd)]);\n return Buffer.from(out).toString('base64').replace(/=/g, '');\n}\n\n/** Generates the x-client-transaction-id header value for X GraphQL requests. */\nexport class ClientTransaction {\n private homePageDocument: XDocument;\n private rowIndex: number | null = null;\n private keyByteIndices: number[] | null = null;\n private key: string | null = null;\n private keyBytes: number[] | null = null;\n private animationKey: string | null = null;\n private isInitialized = false;\n\n constructor(homePageDocument: XDocument) {\n this.homePageDocument = homePageDocument;\n }\n\n static async create(homePageDocument: XDocument): Promise<ClientTransaction> {\n const instance = new ClientTransaction(homePageDocument);\n await instance.initialize();\n return instance;\n }\n\n async initialize(): Promise<void> {\n if (this.isInitialized) return;\n [this.rowIndex, this.keyByteIndices] = await this.getIndices();\n this.key = this.getKey();\n this.keyBytes = getKeyBytes(this.key);\n this.animationKey = this.getAnimationKey(this.keyBytes);\n this.isInitialized = true;\n }\n\n private async getIndices(): Promise<[number, number[]]> {\n const onDemandFileUrl = this.getOnDemandFileUrl();\n const onDemandFileResponse = await fetch(onDemandFileUrl);\n if (!onDemandFileResponse.ok) {\n throw new OnDemandFileFetchError(\n onDemandFileUrl,\n onDemandFileResponse.status,\n onDemandFileResponse.statusText,\n );\n }\n const responseText = await onDemandFileResponse.text();\n\n const indices: number[] = [];\n INDICES_REGEX.lastIndex = 0;\n let match: RegExpExecArray | null = INDICES_REGEX.exec(responseText);\n while (match !== null) {\n if (match[1] !== undefined) indices.push(Number.parseInt(match[1], 10));\n match = INDICES_REGEX.exec(responseText);\n }\n if (!indices.length) throw new KeyByteIndicesExtractionError();\n return [indices[0] ?? 0, indices.slice(1)];\n }\n\n private getOnDemandFileUrl(): string {\n const doc = this.homePageDocument;\n const runtimeSources = Array.from(doc.querySelectorAll('script'))\n .map((script) => script.textContent || '')\n .filter((text) => text.includes(ON_DEMAND_CHUNK_NAME));\n runtimeSources.push(doc.documentElement.outerHTML);\n\n for (const runtimeSource of runtimeSources) {\n const url = resolveOnDemandFileUrlFromRuntime(runtimeSource);\n if (url) return url;\n }\n throw new OnDemandFileUrlResolutionError();\n }\n\n private getKey(): string {\n const element = this.homePageDocument.querySelector(\"[name='twitter-site-verification']\");\n const content = element ? (element.getAttribute('content') ?? '') : '';\n if (!content) throw new SiteVerificationKeyNotFoundError();\n return content;\n }\n\n private getFrames(): XElement[] {\n return Array.from(this.homePageDocument.querySelectorAll(\"[id^='loading-x-anim']\"));\n }\n\n private get2dArray(keyBytes: number[]): number[][] {\n const frames = this.getFrames();\n if (!frames.length) return [[]];\n\n const frame = frames[(keyBytes[5] ?? 0) % 4];\n const firstChild = frame?.children[0];\n const targetChild = firstChild?.children[1];\n const dAttr = targetChild?.getAttribute('d') ?? null;\n if (dAttr === null) return [];\n\n const items = dAttr.substring(9).split('C');\n return items.map((item) => {\n const cleaned = item.replace(/[^\\d]+/g, ' ').trim();\n const parts = cleaned === '' ? [] : cleaned.split(/\\s+/);\n return parts.map((str) => Number.parseInt(str, 10));\n });\n }\n\n private solve(value: number, minVal: number, maxVal: number, rounding: boolean): number {\n const result = (value * (maxVal - minVal)) / 255 + minVal;\n return rounding ? Math.floor(result) : Math.round(result * 100) / 100;\n }\n\n private animate(frames: number[], targetTime: number): string {\n const fromColor = frames.slice(0, 3).concat(1).map(Number);\n const toColor = frames.slice(3, 6).concat(1).map(Number);\n const fromRotation = [0.0];\n const toRotation = [this.solve(frames[6] ?? 0, 60.0, 360.0, true)];\n\n const curves = frames\n .slice(7)\n .map((item, counter) => this.solve(item, isOdd(counter), 1.0, false));\n\n const val = new Cubic(curves).getValue(targetTime);\n const color = interpolate(fromColor, toColor, val).map((value) => (value > 0 ? value : 0));\n const rotation = interpolate(fromRotation, toRotation, val);\n const matrix = convertRotationToMatrix(rotation[0] ?? 0);\n\n const strArr: string[] = color.slice(0, -1).map((value) => Math.round(value).toString(16));\n for (const value of matrix) {\n let rounded = Math.round(value * 100) / 100;\n if (rounded < 0) rounded = -rounded;\n const hexValue = floatToHex(rounded);\n strArr.push(hexValue.startsWith('.') ? `0${hexValue}`.toLowerCase() : hexValue || '0');\n }\n strArr.push('0', '0');\n return strArr.join('').replace(/[.-]/g, '');\n }\n\n private getAnimationKey(keyBytes: number[]): string {\n const totalTime = 4096;\n if (this.rowIndex == null || this.keyByteIndices == null) {\n throw new IndicesNotInitializedError();\n }\n\n const rowIndex = (keyBytes[this.rowIndex] ?? 0) % 16;\n let frameTime = this.keyByteIndices.reduce((acc, idx) => acc * ((keyBytes[idx] ?? 0) % 16), 1);\n frameTime = Math.round(frameTime / 10) * 10;\n\n const arr = this.get2dArray(keyBytes);\n const frameRow = arr[rowIndex];\n if (!frameRow) throw new AnimationFrameDataError(rowIndex);\n\n return this.animate(frameRow, frameTime / totalTime);\n }\n\n /** Generates a transaction id for the given (method, path). Requires initialize(). */\n async generateTransactionId(method: string, path: string, timeNow?: number): Promise<string> {\n if (!this.isInitialized || this.keyBytes == null || this.animationKey == null) {\n throw new ClientTransactionNotInitializedError();\n }\n const t = timeNow ?? Math.floor((Date.now() - EPOCH_SECONDS * 1000) / 1000);\n return assembleTransactionId(this.keyBytes, this.animationKey, method, path, t);\n }\n}\n\nfunction getKeyBytes(key: string): number[] {\n return Array.from(Buffer.from(key, 'base64'));\n}\n\nexport default ClientTransaction;\n","// Cubic bezier interpolation. Vendored + ported from Lqm1/x-client-transaction-id (MIT).\n// Strict-mode-safe (destructured control points) but mathematically identical to upstream.\n\nexport default class Cubic {\n private curves: number[];\n\n constructor(curves: number[]) {\n this.curves = curves;\n }\n\n getValue(time: number): number {\n const [c0 = 0, c1 = 0, c2 = 0, c3 = 0] = this.curves;\n let startGradient = 0;\n let endGradient = 0;\n let start = 0.0;\n let mid = 0.0;\n const endInit = 1.0;\n let end = endInit;\n\n if (time <= 0.0) {\n if (c0 > 0.0) {\n startGradient = c1 / c0;\n } else if (c1 === 0.0 && c2 > 0.0) {\n startGradient = c3 / c2;\n }\n return startGradient * time;\n }\n\n if (time >= 1.0) {\n if (c2 < 1.0) {\n endGradient = (c3 - 1.0) / (c2 - 1.0);\n } else if (c2 === 1.0 && c0 < 1.0) {\n endGradient = (c1 - 1.0) / (c0 - 1.0);\n }\n return 1.0 + endGradient * (time - 1.0);\n }\n\n while (start < end) {\n mid = (start + end) / 2;\n const xEst = this.calculate(c0, c2, mid);\n if (Math.abs(time - xEst) < 0.00001) {\n return this.calculate(c1, c3, mid);\n }\n if (xEst < time) {\n start = mid;\n } else {\n end = mid;\n }\n }\n return this.calculate(c1, c3, mid);\n }\n\n private calculate(a: number, b: number, m: number): number {\n return 3.0 * a * (1 - m) * (1 - m) * m + 3.0 * b * (1 - m) * m * m + m * m * m;\n }\n}\n","// Typed errors for the x-client-transaction-id generator.\n// Vendored + ported from Lqm1/x-client-transaction-id (MIT). See docs/ENGINE-RESEARCH.md §3.\n\ntype ErrorOptionsWithCode = { cause?: unknown; code?: string };\n\nexport class ClientTransactionError extends Error {\n readonly code: string;\n constructor(message: string, options: ErrorOptionsWithCode = {}) {\n super(message, options.cause ? { cause: options.cause } : undefined);\n this.name = new.target.name;\n this.code = options.code ?? 'CLIENT_TRANSACTION_ERROR';\n }\n}\n\nexport class ClientTransactionInitializationError extends ClientTransactionError {\n constructor(message: string, options: ErrorOptionsWithCode = {}) {\n super(message, {\n code: options.code ?? 'CLIENT_TRANSACTION_INITIALIZATION_ERROR',\n cause: options.cause,\n });\n }\n}\n\nexport class OnDemandFileUrlResolutionError extends ClientTransactionInitializationError {\n constructor() {\n super('Unable to resolve the X ondemand chunk URL from the homepage runtime.', {\n code: 'ONDEMAND_FILE_URL_RESOLUTION_ERROR',\n });\n }\n}\n\nexport class OnDemandFileFetchError extends ClientTransactionInitializationError {\n readonly url: string;\n readonly status: number;\n readonly statusText: string;\n constructor(url: string, status: number, statusText: string) {\n super(`Unable to fetch the X ondemand chunk from \"${url}\": ${status} ${statusText}.`, {\n code: 'ONDEMAND_FILE_FETCH_ERROR',\n });\n this.url = url;\n this.status = status;\n this.statusText = statusText;\n }\n}\n\nexport class KeyByteIndicesExtractionError extends ClientTransactionInitializationError {\n constructor() {\n super('Unable to extract key byte indices from the X ondemand chunk.', {\n code: 'KEY_BYTE_INDICES_EXTRACTION_ERROR',\n });\n }\n}\n\nexport class SiteVerificationKeyNotFoundError extends ClientTransactionInitializationError {\n constructor() {\n super('Unable to find the twitter-site-verification meta tag in the homepage document.', {\n code: 'SITE_VERIFICATION_KEY_NOT_FOUND_ERROR',\n });\n }\n}\n\nexport class IndicesNotInitializedError extends ClientTransactionError {\n constructor() {\n super(\n 'ClientTransaction indices are not initialized. Call initialize() before generating animation data.',\n { code: 'INDICES_NOT_INITIALIZED_ERROR' },\n );\n }\n}\n\nexport class AnimationFrameDataError extends ClientTransactionInitializationError {\n readonly rowIndex: number;\n constructor(rowIndex: number) {\n super(\n `Unable to build animation data for row ${rowIndex}. The homepage animation markup may have changed.`,\n { code: 'ANIMATION_FRAME_DATA_ERROR' },\n );\n this.rowIndex = rowIndex;\n }\n}\n\nexport class ClientTransactionNotInitializedError extends ClientTransactionError {\n constructor() {\n super(\n 'ClientTransaction has not been initialized. Call initialize() or use ClientTransaction.create() first.',\n { code: 'CLIENT_TRANSACTION_NOT_INITIALIZED_ERROR' },\n );\n }\n}\n\nexport class HandleXMigrationError extends ClientTransactionError {\n constructor(message: string, options: ErrorOptionsWithCode = {}) {\n super(message, { code: options.code ?? 'HANDLE_X_MIGRATION_ERROR', cause: options.cause });\n }\n}\n\nexport class XHomePageFetchError extends HandleXMigrationError {\n readonly status: number;\n readonly statusText: string;\n constructor(status: number, statusText: string) {\n super(`Unable to fetch the X homepage: ${status} ${statusText}.`, {\n code: 'X_HOMEPAGE_FETCH_ERROR',\n });\n this.status = status;\n this.statusText = statusText;\n }\n}\n\nexport class XMigrationRedirectionError extends HandleXMigrationError {\n readonly status: number;\n readonly statusText: string;\n constructor(status: number, statusText: string) {\n super(`Unable to follow the X migration redirect: ${status} ${statusText}.`, {\n code: 'X_MIGRATION_REDIRECTION_ERROR',\n });\n this.status = status;\n this.statusText = statusText;\n }\n}\n\nexport class XMigrationFormError extends HandleXMigrationError {\n readonly status: number;\n readonly statusText: string;\n constructor(status: number, statusText: string) {\n super(`Unable to submit the X migration form: ${status} ${statusText}.`, {\n code: 'X_MIGRATION_FORM_ERROR',\n });\n this.status = status;\n this.statusText = statusText;\n }\n}\n\nexport class InterpolationInputError extends ClientTransactionError {\n readonly fromLength: number;\n readonly toLength: number;\n constructor(fromLength: number, toLength: number) {\n super(\n `Interpolation requires arrays of the same length, but received ${fromLength} and ${toLength}.`,\n { code: 'INTERPOLATION_INPUT_ERROR' },\n );\n this.fromLength = fromLength;\n this.toLength = toLength;\n }\n}\n","// Array/scalar interpolation. Vendored + ported from Lqm1/x-client-transaction-id (MIT).\nimport { InterpolationInputError } from './errors.ts';\n\nexport function interpolate(fromList: number[], toList: number[], f: number): number[] {\n if (fromList.length !== toList.length) {\n throw new InterpolationInputError(fromList.length, toList.length);\n }\n const out: number[] = [];\n for (let i = 0; i < fromList.length; i++) {\n out.push(interpolateNum(fromList[i] ?? 0, toList[i] ?? 0, f));\n }\n return out;\n}\n\nexport function interpolateNum(\n fromVal: number | boolean,\n toVal: number | boolean,\n f: number,\n): number {\n if (typeof fromVal === 'number' && typeof toVal === 'number') {\n return fromVal * (1 - f) + toVal * f;\n }\n if (typeof fromVal === 'boolean' && typeof toVal === 'boolean') {\n return f < 0.5 ? (fromVal ? 1 : 0) : toVal ? 1 : 0;\n }\n return 0;\n}\n","// Rotation → 2D transform matrix. Vendored + ported from Lqm1/x-client-transaction-id (MIT).\n\n/** Converts a rotation angle in degrees to a [a, b, c, d] transform matrix. */\nexport function convertRotationToMatrix(rotation: number): number[] {\n const rad = (rotation * Math.PI) / 180;\n return [Math.cos(rad), -Math.sin(rad), Math.sin(rad), Math.cos(rad)];\n}\n","// Helpers for the x-client-transaction-id generator. Vendored + ported from\n// Lqm1/x-client-transaction-id (MIT). `handleXMigration` is the network boundary\n// that produces the homepage Document the generator initializes from.\nimport { parseHTML } from 'linkedom';\nimport type { XDocument } from './dom.ts';\nimport { XHomePageFetchError, XMigrationFormError, XMigrationRedirectionError } from './errors.ts';\n\nconst BROWSER_HEADERS: Record<string, string> = {\n accept:\n 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',\n 'accept-language': 'en-US,en;q=0.9',\n 'cache-control': 'no-cache',\n pragma: 'no-cache',\n priority: 'u=0, i',\n 'sec-ch-ua': '\"Google Chrome\";v=\"135\", \"Not-A.Brand\";v=\"8\", \"Chromium\";v=\"135\"',\n 'sec-ch-ua-mobile': '?0',\n 'sec-ch-ua-platform': '\"Windows\"',\n 'sec-fetch-dest': 'document',\n 'sec-fetch-mode': 'navigate',\n 'sec-fetch-site': 'none',\n 'sec-fetch-user': '?1',\n 'upgrade-insecure-requests': '1',\n 'user-agent':\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36',\n};\n\n/** Fetches x.com, following the migration redirect + form, and returns the homepage Document. */\nexport async function handleXMigration(fetchImpl: typeof fetch = fetch): Promise<XDocument> {\n const response = await fetchImpl('https://x.com', { headers: BROWSER_HEADERS });\n if (!response.ok) {\n throw new XHomePageFetchError(response.status, response.statusText);\n }\n\n const htmlText = await response.text();\n let document = parseHTML(htmlText).window.document as unknown as XDocument;\n\n const migrationRedirectionRegex =\n /(http(?:s)?:\\/\\/(?:www\\.)?(twitter|x){1}\\.com(\\/x)?\\/migrate([/?])?tok=[a-zA-Z0-9%\\-_]+)+/i;\n\n const metaRefresh = document.querySelector(\"meta[http-equiv='refresh']\");\n const metaContent = metaRefresh ? metaRefresh.getAttribute('content') || '' : '';\n const migrationRedirectionUrl =\n migrationRedirectionRegex.exec(metaContent) || migrationRedirectionRegex.exec(htmlText);\n\n if (migrationRedirectionUrl) {\n const redirectResponse = await fetchImpl(migrationRedirectionUrl[0]);\n if (!redirectResponse.ok) {\n throw new XMigrationRedirectionError(redirectResponse.status, redirectResponse.statusText);\n }\n document = parseHTML(await redirectResponse.text()).window.document as unknown as XDocument;\n }\n\n const migrationForm =\n document.querySelector(\"form[name='f']\") ||\n document.querySelector(\"form[action='https://x.com/x/migrate']\");\n\n if (migrationForm) {\n const url = migrationForm.getAttribute('action') || 'https://x.com/x/migrate';\n const method = migrationForm.getAttribute('method') || 'POST';\n const requestPayload = new FormData();\n for (const element of Array.from(migrationForm.querySelectorAll('input'))) {\n const name = element.getAttribute('name');\n const value = element.getAttribute('value');\n if (name && value) requestPayload.append(name, value);\n }\n const formResponse = await fetchImpl(url, { method, body: requestPayload });\n if (!formResponse.ok) {\n throw new XMigrationFormError(formResponse.status, formResponse.statusText);\n }\n document = parseHTML(await formResponse.text()).window.document as unknown as XDocument;\n }\n\n return document;\n}\n\n/** Floating-point → hex string (integer part + optional hex fraction). */\nexport function floatToHex(x: number): string {\n const result: string[] = [];\n let n = x;\n let quotient = Math.floor(n);\n const fraction = n - quotient;\n\n while (quotient > 0) {\n quotient = Math.floor(n / 16);\n const remainder = Math.floor(n - quotient * 16);\n if (remainder > 9) {\n result.unshift(String.fromCharCode(remainder + 55));\n } else {\n result.unshift(remainder.toString());\n }\n n = quotient;\n }\n\n if (fraction === 0) return result.join('');\n\n result.push('.');\n let frac = fraction;\n while (frac > 0) {\n frac *= 16;\n const integer = Math.floor(frac);\n frac -= integer;\n if (integer > 9) {\n result.push(String.fromCharCode(integer + 55));\n } else {\n result.push(integer.toString());\n }\n }\n return result.join('');\n}\n\n/** -1.0 for odd numbers, 0.0 for even (used as a cubic control-point seed). */\nexport function isOdd(num: number): number {\n return num % 2 ? -1.0 : 0.0;\n}\n","// The Engine — the only network-facing surface. Wires the transaction-id\n// generator + auth headers + op config + request driver + parser into the\n// high-level research operations the commands consume. Network lives here so\n// command logic stays pure and testable. See docs/ENGINE-RESEARCH.md.\nimport type { SearchResult, ThreadResult, Tweet, TweetPage, UserProfile } from '../types.ts';\nimport type { Cookies } from './auth.ts';\nimport { type ClientResult, type TransactionProvider, createClient } from './client.ts';\nimport { getCookies } from './cookies.ts';\nimport {\n type BuiltRequest,\n type OpName,\n type SearchProduct,\n bookmarksRequest,\n searchRequest,\n tweetDetailRequest,\n userByScreenNameRequest,\n userTweetsRequest,\n} from './ops.ts';\nimport { findDict, parseThread, parseTimeline, parseUserResult } from './parse.ts';\nimport { ClientTransaction, handleXMigration } from './xctid/index.ts';\n\nconst DEFAULT_LIMIT = 40;\n/** Stop paginating after this many consecutive pages with no fresh tweets. */\nconst EMPTY_PAGE_TOLERANCE = 3;\n\n/** A failure surfaced from the network/transport layer. Commands map it to an envelope. */\nexport class EngineError extends Error {\n readonly code: string;\n readonly status?: number;\n constructor(code: string, message: string, status?: number) {\n super(message);\n this.name = 'EngineError';\n this.code = code;\n if (status !== undefined) this.status = status;\n }\n}\n\n/** The transport surface the engine needs — satisfied by createClient, fakeable in tests. */\nexport interface EngineClient {\n get(op: OpName, request: BuiltRequest): Promise<ClientResult>;\n}\n\nexport interface SearchOpts {\n product?: SearchProduct;\n limit?: number;\n}\n\nexport interface UserTweetsOpts {\n replies?: boolean;\n limit?: number;\n /** Stop paginating once a tweet with id <= this is seen (incremental sync watermark). */\n stopAtId?: string;\n}\n\nexport interface PageOpts {\n limit?: number;\n /** Stop paginating once a tweet with id <= this is seen (incremental sync watermark). */\n stopAtId?: string;\n}\n\n/** Snowflake ids are time-ordered; compare as BigInt, falling back to string length/compare. */\nfunction idLte(a: string, b: string): boolean {\n try {\n return BigInt(a) <= BigInt(b);\n } catch {\n return a.length === b.length ? a <= b : a.length < b.length;\n }\n}\n\nexport interface Engine {\n search(query: string, opts?: SearchOpts): Promise<SearchResult>;\n user(handle: string): Promise<UserProfile | null>;\n userTweets(handle: string, opts?: UserTweetsOpts): Promise<TweetPage>;\n bookmarks(opts?: PageOpts): Promise<TweetPage>;\n thread(id: string): Promise<ThreadResult>;\n}\n\nexport interface EngineDeps {\n /** Cookies for auth. Omit to auto-extract from the local browser (getCookies). */\n cookies?: Cookies;\n fetchImpl?: typeof fetch;\n /** Injectable transport (tests). Defaults to a real client over the X API. */\n client?: EngineClient;\n /** Injectable transaction provider (tests). Defaults to the xctid generator. */\n transaction?: TransactionProvider;\n}\n\n/** A lazy x-client-transaction-id provider that (re)initializes from the X homepage. */\nfunction createTransactionProvider(fetchImpl?: typeof fetch): {\n provider: TransactionProvider;\n refresh: () => Promise<void>;\n} {\n let ctPromise: Promise<ClientTransaction> | undefined;\n const init = async (): Promise<ClientTransaction> =>\n ClientTransaction.create(await handleXMigration(fetchImpl));\n const get = (): Promise<ClientTransaction> => {\n if (ctPromise === undefined) ctPromise = init();\n return ctPromise;\n };\n return {\n provider: async (method, path) => (await get()).generateTransactionId(method, path),\n refresh: async () => {\n ctPromise = init();\n await ctPromise;\n },\n };\n}\n\n/** Follows bottom cursors, de-duping by id, until `limit`, `stopAtId`, or exhaustion. */\nasync function paginate(\n fetchPage: (cursor?: string) => Promise<TweetPage>,\n limit: number,\n stopAtId?: string,\n): Promise<TweetPage> {\n const tweets: Tweet[] = [];\n const seen = new Set<string>();\n let cursor: string | undefined;\n let emptyStreak = 0;\n let reachedWatermark = false;\n\n while (tweets.length < limit && !reachedWatermark) {\n const page = await fetchPage(cursor);\n let fresh = 0;\n for (const t of page.tweets) {\n if (stopAtId !== undefined && idLte(t.id, stopAtId)) {\n reachedWatermark = true;\n break;\n }\n if (seen.has(t.id)) continue;\n seen.add(t.id);\n tweets.push(t);\n fresh += 1;\n }\n\n if (reachedWatermark) break;\n if (fresh === 0) {\n emptyStreak += 1;\n if (emptyStreak >= EMPTY_PAGE_TOLERANCE) break;\n } else {\n emptyStreak = 0;\n }\n\n if (page.nextCursor === undefined || page.nextCursor === cursor) break;\n cursor = page.nextCursor;\n }\n\n const out: TweetPage = { tweets: tweets.slice(0, limit) };\n // When we stopped at the watermark the timeline isn't exhausted, but there's\n // nothing newer to fetch, so we intentionally omit nextCursor.\n if (cursor !== undefined && !reachedWatermark) out.nextCursor = cursor;\n return out;\n}\n\nexport function createEngine(deps: EngineDeps): Engine {\n const txn = deps.transaction\n ? { provider: deps.transaction, refresh: async () => {} }\n : createTransactionProvider(deps.fetchImpl);\n\n // Resolve cookies only when we actually build a network client (auto-extract\n // from the browser if none were passed); a test-injected client needs none.\n const client: EngineClient =\n deps.client ??\n createClient({\n cookies: deps.cookies ?? getCookies(),\n transaction: txn.provider,\n ...(deps.fetchImpl ? { fetchImpl: deps.fetchImpl } : {}),\n });\n\n // Runs a request; on a stale-transaction-id NOT_FOUND, refreshes the generator\n // once and retries (the bundle may have rotated). Other errors throw.\n async function call(op: OpName, request: BuiltRequest, retried = false): Promise<unknown> {\n const res = await client.get(op, request);\n if (res.ok) return res.value;\n if (res.error.code === 'NOT_FOUND' && !retried) {\n await txn.refresh();\n return call(op, request, true);\n }\n throw new EngineError(res.error.code, res.error.message, res.error.status);\n }\n\n async function getUser(handle: string): Promise<UserProfile | null> {\n const value = await call('UserByScreenName', userByScreenNameRequest({ screenName: handle }));\n const result = findDict(value, 'result', true)[0];\n return parseUserResult(result);\n }\n\n return {\n async search(query, opts) {\n const product: SearchProduct = opts?.product ?? 'Top';\n const limit = opts?.limit ?? DEFAULT_LIMIT;\n const page = await paginate(async (cursor) => {\n const value = await call('SearchTimeline', searchRequest({ query, product, cursor }));\n return parseTimeline(value);\n }, limit);\n const out: SearchResult = { query, product, tweets: page.tweets };\n if (page.nextCursor !== undefined) out.nextCursor = page.nextCursor;\n return out;\n },\n\n user: getUser,\n\n async userTweets(handle, opts) {\n const profile = await getUser(handle);\n if (!profile) throw new EngineError('NOT_FOUND', `user @${handle} not found`);\n const limit = opts?.limit ?? DEFAULT_LIMIT;\n return paginate(\n async (cursor) => {\n const req = userTweetsRequest({ userId: profile.id, replies: opts?.replies, cursor });\n const value = await call(req.op, req);\n return parseTimeline(value);\n },\n limit,\n opts?.stopAtId,\n );\n },\n\n async bookmarks(opts) {\n const limit = opts?.limit ?? DEFAULT_LIMIT;\n return paginate(\n async (cursor) => {\n const value = await call('Bookmarks', bookmarksRequest({ cursor }));\n return parseTimeline(value);\n },\n limit,\n opts?.stopAtId,\n );\n },\n\n async thread(id) {\n const value = await call('TweetDetail', tweetDetailRequest({ focalTweetId: id }));\n return parseThread(value, id);\n },\n };\n}\n","// Single source of truth for command definitions. Drives CLI help/dispatch and\n// is available to the skill generator. Keep in sync with the runners below.\n\nexport interface CommandDef {\n name: string;\n /** Funnel cost hint shown in help + skill. */\n cost: string;\n summary: string;\n usage: string;\n}\n\nexport const COMMANDS: CommandDef[] = [\n {\n name: 'search',\n cost: 'cheap — the net',\n summary: 'Live X search. Cast a wide net; rank on engagement/recency metadata.',\n usage:\n 'xrelay search \"<query>\" [--limit N] [--product Top|Latest|Media|People]\\n' +\n ' [--from <h>] [--to <h>] [--since YYYY-MM-DD] [--until YYYY-MM-DD]\\n' +\n ' [--lang xx] [--min-faves N] [--min-retweets N] [--filter media|links|replies|-replies ...]',\n },\n {\n name: 'user',\n cost: '1 call',\n summary: 'Profile lookup: bio, followers, verified, counts, joined.',\n usage: 'xrelay user <handle|url>',\n },\n {\n name: 'user-posts',\n cost: 'medium',\n summary: \"A user's timeline (optionally including replies).\",\n usage: 'xrelay user-posts <handle|url> [--replies] [--limit N]',\n },\n {\n name: 'thread',\n cost: 'expensive — full read',\n summary: 'A tweet plus its reply thread. Read only the finalists.',\n usage: 'xrelay thread <id|url>',\n },\n {\n name: 'bookmarks',\n cost: 'cheap — local cache',\n summary: 'Search your saved posts in the local cache. --sync to refresh, --live to hit X.',\n usage:\n 'xrelay bookmarks [-q \"<query>\"] [--limit N] [--sort relevance|newest|likes|views|bookmarks]\\n' +\n ' [--sync] [--repair] [--live]',\n },\n {\n name: 'my-posts',\n cost: 'cheap — local cache',\n summary: 'Search your own posts in the local cache. --sync to refresh, --live to hit X.',\n usage:\n 'xrelay my-posts [-q \"<query>\"] [--limit N] [--sort ...] [--handle <you>] [--sync] [--live]',\n },\n {\n name: 'sync',\n cost: 'medium — incremental',\n summary: 'Pull only NEW bookmarks/posts since the last sync into the local cache.',\n usage: 'xrelay sync bookmarks|posts|all [--handle <you>] [--repair]',\n },\n];\n\nexport const commandNames: string[] = COMMANDS.map((c) => c.name);\n","// Local persistence for the user's cached X posts/bookmarks under ~/.xrelay.\n// A small atomic-ish JSON store keyed by tweet id, with a snowflake watermark\n// (highest cached id) to drive incremental sync. Never throws on read.\n\nimport { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Tweet } from '../types.ts';\n\nexport type CacheSource = 'bookmarks' | 'posts';\n\nexport interface CacheFile {\n source: CacheSource;\n handle?: string;\n syncedAt?: string;\n /** The highest (newest) tweet id cached. */\n watermark?: string;\n /** Tweets keyed by tweet id. */\n tweets: Record<string, Tweet>;\n}\n\n/** The cache directory: an explicit override, else ~/.xrelay. */\nexport function cacheDir(): string {\n return process.env.XRELAY_CACHE_DIR ?? join(homedir(), '.xrelay');\n}\n\n/** The JSON file path for a given source. */\nexport function cachePath(source: CacheSource, dir?: string): string {\n return join(dir ?? cacheDir(), `${source}.json`);\n}\n\n/** Read+parse the cache file; on missing OR unparseable, return a fresh shape. */\nexport function loadCache(source: CacheSource, dir?: string): CacheFile {\n try {\n const raw = readFileSync(cachePath(source, dir), 'utf8');\n return JSON.parse(raw) as CacheFile;\n } catch {\n return { source, tweets: {} };\n }\n}\n\n/** Write the cache as pretty JSON, atomically (temp file then rename). */\nexport function saveCache(file: CacheFile, dir?: string): void {\n const target = cachePath(file.source, dir);\n mkdirSync(dir ?? cacheDir(), { recursive: true });\n const tmp = `${target}.${process.pid}.tmp`;\n writeFileSync(tmp, `${JSON.stringify(file, null, 2)}\\n`);\n renameSync(tmp, target);\n}\n\n/** True if `a` is a higher (newer) snowflake id than `b`. */\nfunction isHigherId(a: string, b: string): boolean {\n try {\n return BigInt(a) > BigInt(b);\n } catch {\n if (a.length !== b.length) return a.length > b.length;\n return a > b;\n }\n}\n\n/**\n * Merge fresh tweets into the file (overwriting existing ids — repair use case),\n * counting only previously-absent ids as `added`, then recompute the watermark\n * as the max id across ALL cached tweets. Mutates `file`.\n */\nexport function mergeTweets(file: CacheFile, fresh: Tweet[]): { added: number } {\n let added = 0;\n for (const t of fresh) {\n if (!(t.id in file.tweets)) added += 1;\n file.tweets[t.id] = t;\n }\n\n let watermark: string | undefined;\n for (const id of Object.keys(file.tweets)) {\n if (watermark === undefined || isHigherId(id, watermark)) watermark = id;\n }\n if (watermark !== undefined) file.watermark = watermark;\n\n return { added };\n}\n\n/** All cached tweets as an array. */\nexport function allTweets(file: CacheFile): Tweet[] {\n return Object.values(file.tweets);\n}\n","// Pure keyword + metadata ranking over locally-cached tweets — the offline\n// search for the user's bookmarks/posts cache. No I/O, no network.\n\nimport type { Tweet } from '../types.ts';\n\nexport type CacheSort = 'relevance' | 'newest' | 'oldest' | 'likes' | 'views' | 'bookmarks';\n\ntype Scored = { tweet: Tweet; score: number };\n\nconst DEFAULT_LIMIT = 20;\n\nfunction tokenize(query: string): string[] {\n return query\n .toLowerCase()\n .split(/\\s+/)\n .filter((token) => token.length > 0);\n}\n\n/** Count non-overlapping occurrences of `needle` in `haystack`. */\nfunction countOccurrences(haystack: string, needle: string): number {\n if (needle.length === 0) return 0;\n let count = 0;\n let from = 0;\n for (;;) {\n const idx = haystack.indexOf(needle, from);\n if (idx === -1) break;\n count += 1;\n from = idx + needle.length;\n }\n return count;\n}\n\nfunction scoreTweet(tweet: Tweet, tokens: string[]): number {\n const haystack = `${tweet.text} ${tweet.author.handle} ${tweet.author.name}`.toLowerCase();\n let score = 0;\n for (const token of tokens) {\n score += countOccurrences(haystack, token);\n }\n return score;\n}\n\n/** BigInt compare of snowflake ids; returns negative/zero/positive. */\nfunction compareIds(a: string, b: string): number {\n const ai = BigInt(a);\n const bi = BigInt(b);\n if (ai < bi) return -1;\n if (ai > bi) return 1;\n return 0;\n}\n\nfunction metric(tweet: Tweet, key: 'likes' | 'views' | 'bookmarks'): number {\n return tweet.metrics[key] ?? 0;\n}\n\nfunction comparator(sort: CacheSort): (a: Scored, b: Scored) => number {\n switch (sort) {\n case 'newest':\n return (a, b) => compareIds(b.tweet.id, a.tweet.id);\n case 'oldest':\n return (a, b) => compareIds(a.tweet.id, b.tweet.id);\n case 'likes':\n return (a, b) => metric(b.tweet, 'likes') - metric(a.tweet, 'likes');\n case 'views':\n return (a, b) => metric(b.tweet, 'views') - metric(a.tweet, 'views');\n case 'bookmarks':\n return (a, b) => metric(b.tweet, 'bookmarks') - metric(a.tweet, 'bookmarks');\n default:\n // relevance: score desc, tie-broken by newest id.\n return (a, b) => b.score - a.score || compareIds(b.tweet.id, a.tweet.id);\n }\n}\n\n/**\n * Rank locally-cached tweets by keyword relevance and/or a metadata sort.\n * Pure and non-mutating. With query tokens, tweets scoring 0 are excluded.\n */\nexport function searchCache(\n tweets: Tweet[],\n query: string,\n opts: { limit?: number; sort?: CacheSort } = {},\n): Tweet[] {\n const tokens = tokenize(query);\n const sort = opts.sort ?? 'relevance';\n const limit = opts.limit ?? DEFAULT_LIMIT;\n\n const scored: Scored[] = [];\n for (const tweet of tweets) {\n const score = scoreTweet(tweet, tokens);\n if (tokens.length > 0 && score === 0) continue;\n scored.push({ tweet, score });\n }\n\n scored.sort(comparator(sort));\n\n return scored.slice(0, limit).map((s) => s.tweet);\n}\n","// Incremental sync into the local cache. Fetches newest-first and early-breaks\n// at the stored watermark (snowflake id), so only tweets newer than the last\n// sync are pulled — never a full refetch (unless --repair). See ENGINE-RESEARCH §6.\nimport type { Engine } from '../engine/index.ts';\nimport { type CacheFile, type CacheSource, loadCache, mergeTweets, saveCache } from './store.ts';\n\nexport interface SyncResult {\n source: CacheSource;\n handle?: string;\n added: number;\n total: number;\n watermark?: string;\n}\n\nexport interface SyncOpts {\n /** Refetch everything and overwrite cached records (repair), ignoring the watermark. */\n repair?: boolean;\n /** Safety cap on how many tweets a single sync will pull. */\n max?: number;\n /** Override the cache directory (tests). */\n dir?: string;\n}\n\nconst DEFAULT_MAX = 100000;\n\nasync function syncInto(\n file: CacheFile,\n fetchPage: (limit: number, stopAtId?: string) => Promise<{ tweets: { id: string }[] }>,\n opts: SyncOpts,\n): Promise<SyncResult> {\n const max = opts.max ?? DEFAULT_MAX;\n const stopAtId = opts.repair ? undefined : file.watermark;\n const page = await fetchPage(max, stopAtId);\n const { added } = mergeTweets(file, page.tweets as CacheFile['tweets'][string][]);\n file.syncedAt = new Date().toISOString();\n saveCache(file, opts.dir);\n const result: SyncResult = {\n source: file.source,\n added,\n total: Object.keys(file.tweets).length,\n };\n if (file.handle !== undefined) result.handle = file.handle;\n if (file.watermark !== undefined) result.watermark = file.watermark;\n return result;\n}\n\nexport function syncBookmarks(engine: Engine, opts: SyncOpts = {}): Promise<SyncResult> {\n const file = loadCache('bookmarks', opts.dir);\n return syncInto(\n file,\n (limit, stopAtId) =>\n engine.bookmarks({ limit, ...(stopAtId !== undefined ? { stopAtId } : {}) }),\n opts,\n );\n}\n\nexport function syncPosts(\n engine: Engine,\n handle: string | undefined,\n opts: SyncOpts = {},\n): Promise<SyncResult> {\n const file = loadCache('posts', opts.dir);\n if (handle) file.handle = handle;\n const h = file.handle;\n if (!h) {\n return Promise.reject(\n new Error('posts sync needs your handle once: `xrelay sync posts --handle <you>`'),\n );\n }\n return syncInto(\n file,\n (limit, stopAtId) =>\n engine.userTweets(h, { limit, ...(stopAtId !== undefined ? { stopAtId } : {}) }),\n opts,\n );\n}\n","// Pure builder: fold typed search flags into X's raw advanced-search string.\n// X parses operators inside the query itself, so we just concatenate them.\n\nexport interface SearchQueryFlags {\n query: string;\n from?: string;\n to?: string;\n since?: string;\n until?: string;\n lang?: string;\n minFaves?: number;\n minRetweets?: number;\n /** `filter:<v>`; a leading `-` becomes `-filter:<v>` (exclude). e.g. media, replies, links. */\n filter?: string[];\n}\n\nexport function buildSearchQuery(flags: SearchQueryFlags): string {\n const parts: string[] = [];\n const base = flags.query.trim();\n if (base) parts.push(base);\n\n if (flags.from) parts.push(`from:${flags.from}`);\n if (flags.to) parts.push(`to:${flags.to}`);\n if (flags.since) parts.push(`since:${flags.since}`);\n if (flags.until) parts.push(`until:${flags.until}`);\n if (flags.lang) parts.push(`lang:${flags.lang}`);\n if (flags.minFaves !== undefined) parts.push(`min_faves:${flags.minFaves}`);\n if (flags.minRetweets !== undefined) parts.push(`min_retweets:${flags.minRetweets}`);\n\n for (const f of flags.filter ?? []) {\n const v = f.trim();\n if (!v) continue;\n parts.push(v.startsWith('-') ? `-filter:${v.slice(1)}` : `filter:${v}`);\n }\n\n return parts.join(' ');\n}\n","// Command runners — thin adapters from parsed options to Engine calls, each\n// returning a JSON envelope. Network/transport errors (EngineError) become\n// clean error envelopes; the runners hold no business logic of their own.\nimport {\n type CacheSort,\n type CacheSource,\n type SyncResult,\n allTweets,\n loadCache,\n searchCache,\n syncBookmarks,\n syncPosts,\n} from '../cache/index.ts';\nimport { type Engine, EngineError } from '../engine/index.ts';\nimport type { SearchProduct } from '../engine/ops.ts';\nimport { err, ok } from '../output.ts';\nimport type {\n Envelope,\n SearchResult,\n ThreadResult,\n Tweet,\n TweetPage,\n UserProfile,\n} from '../types.ts';\nimport { type SearchQueryFlags, buildSearchQuery } from './query.ts';\n\n/** Run an engine call, mapping EngineError (and anything else) to an error envelope. */\nasync function guard<T>(command: string, fn: () => Promise<T>): Promise<Envelope<T>> {\n try {\n return ok(command, await fn());\n } catch (e) {\n if (e instanceof EngineError) {\n const hint =\n e.code === 'AUTH_FAILED'\n ? 'Re-log into x.com in your browser, or set XRELAY_COOKIES.'\n : e.code === 'FEATURE_DRIFT'\n ? 'X rotated its API; refresh the query-ids/features in src/engine/ops.ts.'\n : undefined;\n return err(command, e.code, e.message, hint);\n }\n return err(command, 'FETCH_FAILED', e instanceof Error ? e.message : String(e));\n }\n}\n\nexport interface SearchCommandOpts extends Omit<SearchQueryFlags, 'query'> {\n query: string;\n limit?: number;\n product?: SearchProduct;\n}\n\nexport function runSearch(\n engine: Engine,\n opts: SearchCommandOpts,\n): Promise<Envelope<SearchResult>> {\n const raw = buildSearchQuery(opts);\n if (!raw) return Promise.resolve(err('search', 'INVALID_INPUT', 'empty query'));\n return guard('search', () =>\n engine.search(raw, {\n ...(opts.product ? { product: opts.product } : {}),\n ...(opts.limit !== undefined ? { limit: opts.limit } : {}),\n }),\n );\n}\n\nexport function runUser(engine: Engine, handle: string): Promise<Envelope<UserProfile | null>> {\n if (!handle) return Promise.resolve(err('user', 'INVALID_INPUT', 'missing handle'));\n return guard('user', () => engine.user(handle));\n}\n\nexport interface UserPostsCommandOpts {\n handle: string;\n replies?: boolean;\n limit?: number;\n}\n\nexport function runUserPosts(\n engine: Engine,\n opts: UserPostsCommandOpts,\n): Promise<Envelope<TweetPage>> {\n if (!opts.handle) return Promise.resolve(err('user-posts', 'INVALID_INPUT', 'missing handle'));\n return guard('user-posts', () =>\n engine.userTweets(opts.handle, {\n ...(opts.replies ? { replies: true } : {}),\n ...(opts.limit !== undefined ? { limit: opts.limit } : {}),\n }),\n );\n}\n\nexport function runThread(engine: Engine, id: string): Promise<Envelope<ThreadResult>> {\n if (!id) return Promise.resolve(err('thread', 'INVALID_INPUT', 'missing tweet id/url'));\n return guard('thread', () => engine.thread(id));\n}\n\n// ── cache-backed: bookmarks + my-posts ──────────────────────────────────────\n\nexport interface CacheViewOpts {\n query?: string;\n limit?: number;\n sort?: CacheSort;\n /** Hit X directly instead of the local cache. */\n live?: boolean;\n /** Refresh the cache (incremental) before reading. */\n sync?: boolean;\n /** With sync: refetch everything and patch records. */\n repair?: boolean;\n /** With sync: cap how many tweets to pull this run. */\n max?: number;\n}\n\nfunction syncOpts(opts: { repair?: boolean; max?: number }): { repair?: boolean; max?: number } {\n return {\n ...(opts.repair ? { repair: true } : {}),\n ...(opts.max !== undefined ? { max: opts.max } : {}),\n };\n}\n\nexport interface CacheView {\n source: CacheSource;\n cached: boolean;\n total?: number;\n syncedAt?: string;\n added?: number;\n tweets: Tweet[];\n hint?: string;\n}\n\nexport function runBookmarks(\n engine: Engine,\n opts: CacheViewOpts = {},\n): Promise<Envelope<CacheView | TweetPage>> {\n if (opts.live) {\n return guard('bookmarks', () =>\n engine.bookmarks({ ...(opts.limit !== undefined ? { limit: opts.limit } : {}) }),\n );\n }\n return guard('bookmarks', async () => {\n let added: number | undefined;\n if (opts.sync || opts.repair) {\n const r = await syncBookmarks(engine, syncOpts(opts));\n added = r.added;\n }\n return viewCache('bookmarks', opts, added);\n });\n}\n\nexport interface MyPostsOpts extends CacheViewOpts {\n handle?: string;\n}\n\nexport function runMyPosts(\n engine: Engine,\n opts: MyPostsOpts = {},\n): Promise<Envelope<CacheView | TweetPage>> {\n if (opts.live) {\n if (!opts.handle) {\n return Promise.resolve(err('my-posts', 'INVALID_INPUT', '--live needs --handle <you>'));\n }\n return guard('my-posts', () =>\n engine.userTweets(opts.handle as string, {\n ...(opts.limit !== undefined ? { limit: opts.limit } : {}),\n }),\n );\n }\n return guard('my-posts', async () => {\n let added: number | undefined;\n if (opts.sync || opts.repair) {\n const r = await syncPosts(engine, opts.handle, syncOpts(opts));\n added = r.added;\n }\n return viewCache('posts', opts, added);\n });\n}\n\nfunction viewCache(source: CacheSource, opts: CacheViewOpts, added?: number): CacheView {\n const file = loadCache(source);\n const tweets = searchCache(allTweets(file), opts.query ?? '', {\n ...(opts.limit !== undefined ? { limit: opts.limit } : {}),\n ...(opts.sort ? { sort: opts.sort } : {}),\n });\n const total = Object.keys(file.tweets).length;\n const view: CacheView = { source, cached: true, total, tweets };\n if (file.syncedAt !== undefined) view.syncedAt = file.syncedAt;\n if (added !== undefined) view.added = added;\n if (total === 0) {\n view.hint = `cache is empty — run \\`xrelay sync ${source}${source === 'posts' ? ' --handle <you>' : ''}\\` first (or pass --live).`;\n }\n return view;\n}\n\n// ── sync ────────────────────────────────────────────────────────────────────\n\nexport interface SyncCommandOpts {\n source: 'bookmarks' | 'posts' | 'all';\n handle?: string;\n repair?: boolean;\n max?: number;\n}\n\nexport function runSync(engine: Engine, opts: SyncCommandOpts): Promise<Envelope<SyncResult[]>> {\n const so = syncOpts(opts);\n return guard('sync', async () => {\n const results: SyncResult[] = [];\n if (opts.source === 'bookmarks' || opts.source === 'all') {\n results.push(await syncBookmarks(engine, so));\n }\n if (opts.source === 'posts' || opts.source === 'all') {\n results.push(await syncPosts(engine, opts.handle, so));\n }\n return results;\n });\n}\n","#!/usr/bin/env node\n// ─── xrelay CLI ───────────────────────────────────────────────────────────\n// Parses args, dispatches a command against the Engine, prints a JSON envelope\n// to stdout. Errors print an error envelope to stdout and exit non-zero.\nimport { fileURLToPath } from 'node:url';\nimport type { CacheSort } from './cache/index.ts';\nimport {\n type CacheViewOpts,\n type SearchCommandOpts,\n runBookmarks,\n runMyPosts,\n runSearch,\n runSync,\n runThread,\n runUser,\n runUserPosts,\n} from './commands/index.ts';\nimport { COMMANDS, commandNames } from './commands/registry.ts';\nimport { type Engine, createEngine } from './engine/index.ts';\nimport type { SearchProduct } from './engine/ops.ts';\nimport { extractHandle, extractTweetId } from './ids.ts';\nimport { err, toJson } from './output.ts';\nimport type { Envelope } from './types.ts';\n\nconst VALUE_FLAGS = new Set([\n 'limit',\n 'product',\n 'from',\n 'to',\n 'since',\n 'until',\n 'lang',\n 'min-faves',\n 'min-retweets',\n 'filter',\n 'query',\n 'sort',\n 'handle',\n 'max',\n]);\nconst BOOL_FLAGS = new Set(['replies', 'sync', 'live', 'repair']);\n/** Single-dash aliases. */\nconst SHORT_FLAGS: Record<string, string> = { q: 'query' };\n\nexport interface ParsedArgs {\n command?: string;\n positionals: string[];\n flags: Record<string, string[]>;\n bools: Set<string>;\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const positionals: string[] = [];\n const flags: Record<string, string[]> = {};\n const bools = new Set<string>();\n let command: string | undefined;\n\n for (let i = 0; i < argv.length; i++) {\n const token = argv[i];\n if (token === undefined) continue;\n const name = token.startsWith('--')\n ? token.slice(2)\n : token.startsWith('-') && token.length > 1\n ? SHORT_FLAGS[token.slice(1)]\n : undefined;\n if (name !== undefined) {\n if (BOOL_FLAGS.has(name)) {\n bools.add(name);\n } else if (VALUE_FLAGS.has(name)) {\n const value = argv[i + 1];\n if (value !== undefined) {\n const existing = flags[name] ?? [];\n existing.push(value);\n flags[name] = existing;\n i += 1;\n }\n }\n continue;\n }\n if (command === undefined) command = token;\n else positionals.push(token);\n }\n\n return { command, positionals, flags, bools };\n}\n\nconst first = (p: ParsedArgs, name: string): string | undefined => p.flags[name]?.[0];\nconst num = (p: ParsedArgs, name: string): number | undefined => {\n const v = first(p, name);\n if (v === undefined) return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n};\n\nconst PRODUCTS = new Set<SearchProduct>(['Top', 'Latest', 'Media', 'People']);\nconst SORTS = new Set<CacheSort>(['relevance', 'newest', 'oldest', 'likes', 'views', 'bookmarks']);\n\nfunction buildCacheOpts(parsed: ParsedArgs): CacheViewOpts {\n const limit = num(parsed, 'limit');\n const sort = first(parsed, 'sort');\n return {\n ...(first(parsed, 'query') ? { query: first(parsed, 'query') } : {}),\n ...(limit !== undefined ? { limit } : {}),\n ...(sort && SORTS.has(sort as CacheSort) ? { sort: sort as CacheSort } : {}),\n ...(parsed.bools.has('live') ? { live: true } : {}),\n ...(parsed.bools.has('sync') ? { sync: true } : {}),\n ...(parsed.bools.has('repair') ? { repair: true } : {}),\n ...(num(parsed, 'max') !== undefined ? { max: num(parsed, 'max') } : {}),\n };\n}\n\nfunction helpText(): string {\n const lines = ['xrelay — deep-research over X/Twitter', '', 'Commands:'];\n for (const c of COMMANDS) {\n lines.push(` ${c.name.padEnd(11)} ${c.summary} [${c.cost}]`);\n }\n lines.push('', 'Run `xrelay <command>` with --help-style usage in SKILL.md.');\n return lines.join('\\n');\n}\n\nfunction buildSearchOpts(parsed: ParsedArgs): SearchCommandOpts {\n const product = first(parsed, 'product');\n const limit = num(parsed, 'limit');\n const minFaves = num(parsed, 'min-faves');\n const minRetweets = num(parsed, 'min-retweets');\n return {\n query: parsed.positionals.join(' '),\n ...(limit !== undefined ? { limit } : {}),\n ...(product && PRODUCTS.has(product as SearchProduct)\n ? { product: product as SearchProduct }\n : {}),\n ...(first(parsed, 'from') ? { from: first(parsed, 'from') } : {}),\n ...(first(parsed, 'to') ? { to: first(parsed, 'to') } : {}),\n ...(first(parsed, 'since') ? { since: first(parsed, 'since') } : {}),\n ...(first(parsed, 'until') ? { until: first(parsed, 'until') } : {}),\n ...(first(parsed, 'lang') ? { lang: first(parsed, 'lang') } : {}),\n ...(minFaves !== undefined ? { minFaves } : {}),\n ...(minRetweets !== undefined ? { minRetweets } : {}),\n ...(parsed.flags.filter ? { filter: parsed.flags.filter } : {}),\n };\n}\n\n/** Dispatch parsed args against an engine. Returns an envelope (does not print). */\nexport async function dispatch(parsed: ParsedArgs, engine: Engine): Promise<Envelope<unknown>> {\n const { command } = parsed;\n const target = parsed.positionals[0] ?? '';\n\n switch (command) {\n case 'search':\n return runSearch(engine, buildSearchOpts(parsed));\n case 'user':\n return runUser(engine, extractHandle(target) ?? target);\n case 'user-posts':\n return runUserPosts(engine, {\n handle: extractHandle(target) ?? target,\n replies: parsed.bools.has('replies'),\n ...(num(parsed, 'limit') !== undefined ? { limit: num(parsed, 'limit') } : {}),\n });\n case 'thread':\n return runThread(engine, extractTweetId(target) ?? target);\n case 'bookmarks':\n return runBookmarks(engine, buildCacheOpts(parsed));\n case 'my-posts':\n return runMyPosts(engine, {\n ...buildCacheOpts(parsed),\n ...(first(parsed, 'handle') ? { handle: first(parsed, 'handle') } : {}),\n });\n case 'sync': {\n const source = target === 'posts' || target === 'all' ? target : 'bookmarks';\n return runSync(engine, {\n source,\n ...(first(parsed, 'handle') ? { handle: first(parsed, 'handle') } : {}),\n repair: parsed.bools.has('repair'),\n ...(num(parsed, 'max') !== undefined ? { max: num(parsed, 'max') } : {}),\n });\n }\n default:\n return err('cli', 'UNKNOWN_COMMAND', `unknown command: ${command ?? '(none)'}`);\n }\n}\n\nexport async function run(argv: string[], engine?: Engine): Promise<number> {\n const parsed = parseArgs(argv);\n if (parsed.command === undefined || parsed.command === 'help') {\n process.stdout.write(`${helpText()}\\n`);\n return 0;\n }\n if (!commandNames.includes(parsed.command)) {\n process.stdout.write(\n `${toJson(err('cli', 'UNKNOWN_COMMAND', `unknown command: ${parsed.command}`))}\\n`,\n );\n return 2;\n }\n const eng = engine ?? createEngine({});\n const envelope = await dispatch(parsed, eng);\n process.stdout.write(`${toJson(envelope)}\\n`);\n return envelope.ok ? 0 : 1;\n}\n\nconst isEntry =\n import.meta.main === true ||\n (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]);\n\nif (isEntry) {\n run(process.argv.slice(2)).then(\n (code) => {\n process.exitCode = code;\n },\n (e) => {\n process.stdout.write(\n `${toJson(err('cli', 'FATAL', e instanceof Error ? e.message : String(e)))}\\n`,\n );\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":"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","names":["first","err","body","keychainSecret","first","num","homedir","join","DEFAULT_LIMIT"]}
|