1+ // bro bridge —— 后台 service worker
2+ // ---------------------------------------------------------------------------
3+ // 只做两件事:
4+ // 1) 特权抓取:借 host_permissions,代表前端读取搜索引擎等站点的响应内容(不受 CORS 限制);
5+ // 2) 站点代理:在本机后台标签页中托管 Kimi / DeepSeek,并通过 content script 驱动其登录与对话。
6+ // 全部运行在浏览器内部,不依赖 Node / npm / Chromium 等外部环境。
7+ // ---------------------------------------------------------------------------
8+
9+ const SITES = {
10+ kimi : { url : 'https://www.kimi.com/' } ,
11+ deepseek : { url : 'https://chat.deepseek.com/' } ,
12+ } ;
13+
14+ const siteTabs = new Map ( ) ; // site -> tabId
15+ const sleep = ( ms ) => new Promise ( ( r ) => setTimeout ( r , ms ) ) ;
16+
17+ /* ------------------------------ 特权抓取 ------------------------------ */
18+ async function fetchText ( url ) {
19+ const res = await fetch ( url , {
20+ method : 'GET' ,
21+ credentials : 'include' , // 带上本机浏览器已有的 Cookie,提高结果页可用性
22+ redirect : 'follow' ,
23+ cache : 'no-store' ,
24+ headers : { 'Accept-Language' : 'zh-CN,zh;q=0.9,en;q=0.8' } ,
25+ } ) ;
26+ const text = await res . text ( ) ;
27+ if ( ! res . ok ) throw new Error ( `目标站点返回 ${ res . status } ` ) ;
28+ return { status : res . status , finalUrl : res . url , text } ;
29+ }
30+
31+ /* ------------------------------ 站点代理 ------------------------------ */
32+ async function ensureTab ( site ) {
33+ const cfg = SITES [ site ] ;
34+ if ( ! cfg ) throw new Error ( `未知站点:${ site } ` ) ;
35+
36+ const existing = siteTabs . get ( site ) ;
37+ if ( existing != null ) {
38+ try {
39+ await chrome . tabs . get ( existing ) ;
40+ return existing ;
41+ } catch {
42+ siteTabs . delete ( site ) ;
43+ }
44+ }
45+
46+ const tab = await chrome . tabs . create ( { url : cfg . url , active : false } ) ;
47+ siteTabs . set ( site , tab . id ) ;
48+ return tab . id ;
49+ }
50+
51+ // content script 可能尚未注入,带重试地发送消息
52+ async function sendToTab ( tabId , message , { retries = 25 , delay = 800 } = { } ) {
53+ let lastErr ;
54+ for ( let i = 0 ; i < retries ; i ++ ) {
55+ try {
56+ return await chrome . tabs . sendMessage ( tabId , message ) ;
57+ } catch ( err ) {
58+ lastErr = err ;
59+ await sleep ( delay ) ;
60+ }
61+ }
62+ throw new Error ( `无法与站点页面通信:${ lastErr ?. message || lastErr } ` ) ;
63+ }
64+
65+ async function aiCall ( site , cmd , payload = { } ) {
66+ const tabId = await ensureTab ( site ) ;
67+ return sendToTab ( tabId , { cmd, ...payload } ) ;
68+ }
69+
70+ /* --------------------------- 消息分发入口 --------------------------- */
71+ async function handle ( method , params = { } ) {
72+ switch ( method ) {
73+ case 'ping' :
74+ return { pong : true } ;
75+ case 'fetch' :
76+ return fetchText ( params . url ) ;
77+
78+ case 'ai.open' :
79+ return aiCall ( params . site , 'state' ) ;
80+ case 'ai.state' :
81+ return aiCall ( params . site , 'state' ) ;
82+ case 'ai.login' :
83+ return aiCall ( params . site , 'login' , {
84+ username : params . username ,
85+ password : params . password ,
86+ captcha : params . captcha ,
87+ } ) ;
88+ case 'ai.chat' :
89+ return aiCall ( params . site , 'chat' , { text : params . text , images : params . images || [ ] } ) ;
90+ case 'ai.newChat' :
91+ return aiCall ( params . site , 'newChat' ) ;
92+ case 'ai.reset' : {
93+ const tabId = siteTabs . get ( params . site ) ;
94+ if ( tabId != null ) {
95+ await chrome . tabs . remove ( tabId ) . catch ( ( ) => { } ) ;
96+ siteTabs . delete ( params . site ) ;
97+ }
98+ return { ok : true } ;
99+ }
100+ default :
101+ throw new Error ( `未知方法:${ method } ` ) ;
102+ }
103+ }
104+
105+ chrome . runtime . onMessage . addListener ( ( msg , _sender , sendResponse ) => {
106+ if ( ! msg || msg . type !== 'bro' ) return undefined ;
107+ handle ( msg . method , msg . params )
108+ . then ( ( data ) => sendResponse ( { ok : true , data } ) )
109+ . catch ( ( err ) => sendResponse ( { ok : false , error : String ( err ?. message || err ) } ) ) ;
110+ return true ; // 异步响应
111+ } ) ;
112+
113+ // 用户手动关闭托管标签页时同步清理映射
114+ chrome . tabs . onRemoved . addListener ( ( tabId ) => {
115+ for ( const [ site , id ] of siteTabs . entries ( ) ) {
116+ if ( id === tabId ) siteTabs . delete ( site ) ;
117+ }
118+ } ) ;
0 commit comments