Skip to content

[Bug] twitter/search 适配器失效:webpack module ID 和 GraphQL queryId 均已过期 #36

@JohnS3248

Description

@JohnS3248

环境

  • bb-browser: v0.10.1
  • macOS arm64, Chrome 146
  • bb-sites: 最新(bb-browser site update 后仍复现)

问题描述

twitter/search 适配器硬编码了两个 X.com 会定期轮换的值,导致适配器完全不可用。

复现

bb-browser site twitter/search "test" --json
# 错误: TypeError: Cannot read properties of undefined (reading 'call')
#   at g (https://x.com/:341:171705)

根因

~/.bb-browser/bb-sites/twitter/search.js 中有两个硬编码值已过期:

问题 1: webpack module ID 过期

// 第 26 行
const txMod = __webpack_require__(83914);  // ← 已失效
const genTxId = txMod.jJ;

当前 X.com 的 main.69383b5a.js 中,jJ 导出所在模块 ID 已变为 938838

curl -s "https://abs.twimg.com/responsive-web/client-web/main.69383b5a.js" | \
  grep -o '.[0-9]\{3,6\}:.\{0,5\}(e,t,n)=>{"use strict";n.d(t,{K4:()=>a,ZP:()=>l,jJ:()=>s})'
# 输出: ,938838:(e,t,n)=>...

问题 2: GraphQL queryId 过期

// 第 30 行
const path = '/i/api/graphql/oKkjeoNFNQN7IeK7AHYc0A/SearchTimeline';  // ← 404

当前 queryId 为 GcXk9vN_d1jUfHNqLacXQA

curl -s "https://abs.twimg.com/responsive-web/client-web/main.69383b5a.js" | \
  grep -o '.\{0,50\}SearchTimeline.\{0,50\}' | grep queryId
# 输出: queryId:"GcXk9vN_d1jUfHNqLacXQA",operationName:"SearchTimeline"

问题 3: 适配器执行上下文与页面上下文不同

手动将 module ID 和 queryId 都更新为最新值后,适配器调用 API 成功但返回 0 条推文(只有 cursor entries)。

同样的代码通过 bb-browser eval 在页面主线程中执行时,能正常返回 19 条推文。

说明适配器的运行环境与页面 JS 主线程上下文存在差异,导致 webpack 模块不可用或 genTxId 生成了无效的 transaction ID。X.com 对无效 x-client-transaction-id 的处理是返回空结果而非 403。

临时解决方案

通过 bb-browser eval 直接在 x.com 页面上下文中执行搜索脚本:

bb-browser open "https://x.com/search?q=test&src=typed_query"
# 等待页面加载后
bb-browser eval "$(cat <<'JSEOF'
var ct0 = document.cookie.split(";").map(function(c){return c.trim()})
  .find(function(c){return c.startsWith("ct0=")}).split("=")[1];
var wr;
window.webpackChunk_twitter_responsive_web.push([["__bb"],{},function(r){wr=r}]);
var txMod = wr(938838);
var genTxId = txMod.jJ;
var path = "/i/api/graphql/GcXk9vN_d1jUfHNqLacXQA/SearchTimeline";
genTxId("x.com", path, "GET").then(function(txId) {
  var v = JSON.stringify({rawQuery: "test", count: 20, querySource: "typed_query", product: "Top"});
  var f = JSON.stringify({rweb_video_screen_enabled:false,
    profile_label_improvements_pcf_label_in_post_enabled:true,
    responsive_web_graphql_timeline_navigation_enabled:true,
    responsive_web_graphql_skip_user_profile_image_extensions_enabled:false,
    longform_notetweets_consumption_enabled:true,
    view_counts_everywhere_api_enabled:true,
    tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled:true,
    longform_notetweets_rich_text_read_enabled:true,
    responsive_web_enhance_cards_enabled:false});
  return fetch(path+"?variables="+encodeURIComponent(v)+"&features="+encodeURIComponent(f), {
    headers: {"Authorization":"Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA",
      "X-Csrf-Token":ct0,"X-Twitter-Auth-Type":"OAuth2Session",
      "X-Twitter-Active-User":"yes","X-Client-Transaction-Id":txId},
    credentials:"include"});
}).then(function(r){return r.json()}).then(function(d){
  // ... 解析 tweets ...
});
JSEOF
)"
# 成功返回 19 条推文

这说明 API 本身可用,问题在于适配器的执行上下文。

建议

改为动态发现

X.com 每 2-4 周轮换这些值,硬编码不可持续。建议改为运行时自动发现:

// 动态发现 genTxId 函数
let __webpack_require__;
window.webpackChunk_twitter_responsive_web.push(
  [['__bb_auto'], {}, (req) => { __webpack_require__ = req; }]
);
const cache = __webpack_require__.c || {};
let genTxId;
for (const [id, mod] of Object.entries(cache)) {
  if (mod.exports && typeof mod.exports.jJ === 'function') {
    genTxId = mod.exports.jJ;
    break;
  }
}

// 动态发现 queryId
let queryId;
for (const [id, mod] of Object.entries(cache)) {
  const exp = mod.exports;
  if (exp && exp.operationName === 'SearchTimeline') {
    queryId = exp.queryId;
    break;
  }
}

感谢开发这么好用的工具!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions