mooncat-browser 0.1.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/README.md +213 -0
- package/browser-op/backend/browserd.cjs +1004 -0
- package/browser-op/backend/rpc-client.cjs +64 -0
- package/browser-op/backend/state.cjs +51 -0
- package/browser-op/cdp/capture-inject.js +426 -0
- package/browser-op/cdp/capture-inject.ts +426 -0
- package/browser-op/cdp/capture-service.cjs +172 -0
- package/browser-op/cdp/chrome-launcher.cjs +370 -0
- package/browser-op/cdp/chrome-path.cjs +57 -0
- package/browser-op/cdp/state.cjs +89 -0
- package/browser-op/extension/extension-detect.cjs +228 -0
- package/browser-op/extension/server.cjs +197 -0
- package/browser-op/extension/service.cjs +228 -0
- package/browser-op/extension/state.cjs +78 -0
- package/browser-op/index.cjs +389 -0
- package/browser-op/package.json +17 -0
- package/browser-op/py/behavior.py +138 -0
- package/browser-op/py/browser.py +340 -0
- package/browser-op/py/captcha.py +115 -0
- package/browser-op/py/crawler.py +125 -0
- package/browser-op/py/examples/01_open_and_probe.py +48 -0
- package/browser-op/py/examples/02_reuse_and_probe.py +66 -0
- package/browser-op/py/examples/03_interact.py +66 -0
- package/browser-op/py/find.py +150 -0
- package/browser-op/py/honeypot.py +73 -0
- package/browser-op/py/humanize.py +392 -0
- package/browser-op/py/image.py +186 -0
- package/browser-op/py/interact.py +193 -0
- package/browser-op/py/markdown.py +38 -0
- package/browser-op/py/pyproject.toml +32 -0
- package/browser-op/py/ready.py +208 -0
- package/browser-op/py/scroll.py +180 -0
- package/browser-op/py/upload.py +103 -0
- package/browser-op/py/visual_target.py +47 -0
- package/browser-op/py/visualize.py +91 -0
- package/browser-op/state.cjs +63 -0
- package/browser-op/web/behavior.js +153 -0
- package/browser-op/web/browser.js +231 -0
- package/browser-op/web/captcha.js +85 -0
- package/browser-op/web/crawler.js +109 -0
- package/browser-op/web/find.js +147 -0
- package/browser-op/web/honeypot.js +68 -0
- package/browser-op/web/humanize.js +522 -0
- package/browser-op/web/image.js +177 -0
- package/browser-op/web/interact.js +169 -0
- package/browser-op/web/markdown.js +80 -0
- package/browser-op/web/ready.js +295 -0
- package/browser-op/web/scroll.js +167 -0
- package/browser-op/web/upload.js +116 -0
- package/browser-op/web/visual-runtime.inject.cjs +6 -0
- package/browser-op/webplater/.env.example +7 -0
- package/browser-op/webplater/ARCHITECTURE.md +102 -0
- package/browser-op/webplater/dist/chrome-mv3/assets/popup-BUZEUmsx.css +1 -0
- package/browser-op/webplater/dist/chrome-mv3/background.js +2 -0
- package/browser-op/webplater/dist/chrome-mv3/capture.js +310 -0
- package/browser-op/webplater/dist/chrome-mv3/chunks/_virtual_wxt-html-plugins-DPbbfBKe.js +1 -0
- package/browser-op/webplater/dist/chrome-mv3/chunks/offscreen-CFXYw9Mo.js +1 -0
- package/browser-op/webplater/dist/chrome-mv3/chunks/popup-C-lpxZZO.js +1 -0
- package/browser-op/webplater/dist/chrome-mv3/content-scripts/content.js +7 -0
- package/browser-op/webplater/dist/chrome-mv3/manifest.json +1 -0
- package/browser-op/webplater/dist/chrome-mv3/offscreen.html +16 -0
- package/browser-op/webplater/dist/chrome-mv3/popup.html +31 -0
- package/browser-op/webplater/entrypoints/background.ts +938 -0
- package/browser-op/webplater/entrypoints/content.ts +1150 -0
- package/browser-op/webplater/entrypoints/offscreen/index.html +15 -0
- package/browser-op/webplater/entrypoints/offscreen/main.ts +161 -0
- package/browser-op/webplater/entrypoints/popup/index.html +29 -0
- package/browser-op/webplater/entrypoints/popup/main.ts +61 -0
- package/browser-op/webplater/entrypoints/popup/style.css +100 -0
- package/browser-op/webplater/lib/snapshot.ts +352 -0
- package/browser-op/webplater/package.json +29 -0
- package/browser-op/webplater/pnpm-lock.yaml +3411 -0
- package/browser-op/webplater/public/capture.js +310 -0
- package/browser-op/webplater/scripts/publish-extension.mjs +176 -0
- package/browser-op/webplater/tsconfig.json +19 -0
- package/browser-op/webplater/wxt.config.ts +34 -0
- package/dist/actions.md +102 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +278 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +94 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +277 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +61 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +119 -0
- package/dist/config.js.map +1 -0
- package/dist/protocol.d.ts +195 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +11 -0
- package/dist/protocol.js.map +1 -0
- package/dist/server.d.ts +66 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +259 -0
- package/dist/server.js.map +1 -0
- package/package.json +78 -0
- package/schemas/browser.clearCookies.schema.json +13 -0
- package/schemas/browser.close.schema.json +9 -0
- package/schemas/browser.getCookies.schema.json +13 -0
- package/schemas/browser.getDownload.schema.json +15 -0
- package/schemas/browser.health.schema.json +9 -0
- package/schemas/browser.listDownloads.schema.json +16 -0
- package/schemas/browser.listTabs.schema.json +9 -0
- package/schemas/browser.newTab.schema.json +15 -0
- package/schemas/browser.open.schema.json +15 -0
- package/schemas/browser.operate.schema.json +15 -0
- package/schemas/browser.reuseTab.schema.json +15 -0
- package/schemas/browser.setCookies.schema.json +15 -0
- package/schemas/browser.waitFor.schema.json +15 -0
- package/schemas/browser.waitForDownload.schema.json +15 -0
- package/skills/browser/SKILL.md +110 -0
- package/skills/browser/references/collect.md +163 -0
- package/skills/browser/references/high-risk.md +161 -0
- package/skills/browser/references/operate-actions.md +92 -0
- package/skills/browser/references/probing.md +302 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# WebPlater 架构
|
|
2
|
+
|
|
3
|
+
## 完整调用路径
|
|
4
|
+
|
|
5
|
+
业务脚本
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
require('./lib/web/browser')
|
|
9
|
+
open({ routeMode:'plugin' 或 'auto' })
|
|
10
|
+
↓
|
|
11
|
+
browser.js
|
|
12
|
+
ensureBrowserd()
|
|
13
|
+
↓
|
|
14
|
+
browserd 启动
|
|
15
|
+
1. 监听 IPC :17322
|
|
16
|
+
2. 监听插件 WS :17321
|
|
17
|
+
3. 启动 Chrome,使用 browser-op profile
|
|
18
|
+
↓
|
|
19
|
+
Chrome 加载已安装的 WebPlater 扩展
|
|
20
|
+
↓
|
|
21
|
+
WebPlater background 被 Chrome 唤醒
|
|
22
|
+
background 调用 ensureOffscreen()
|
|
23
|
+
↓
|
|
24
|
+
offscreen.html 被创建
|
|
25
|
+
offscreen.ts 连接 ws://127.0.0.1:17321
|
|
26
|
+
↓
|
|
27
|
+
browserd 收到 hello
|
|
28
|
+
标记 extensionConnected = true
|
|
29
|
+
↓
|
|
30
|
+
open() 返回 browserHandle
|
|
31
|
+
{ mode:'extension', ownerId:'default', extensionId, version }
|
|
32
|
+
↓
|
|
33
|
+
newTab / operate / listTabs
|
|
34
|
+
browser.js -> browserd :17322 -> WebPluginServer :17321 -> offscreen -> background -> tabs/content/scripting
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 关键原则
|
|
38
|
+
|
|
39
|
+
**browser 技能打开浏览器这一步仍然由 `open()` 完成。**
|
|
40
|
+
|
|
41
|
+
用户调用的 API 不变:
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
const { open, newTab, operate } = require('./lib/web/browser')
|
|
45
|
+
|
|
46
|
+
const bh = await open({ routeMode: 'plugin', headless: false })
|
|
47
|
+
const ph = await newTab(bh, { url: 'https://www.bing.com' })
|
|
48
|
+
await operate(ph, { action: 'fill', selector: '#q', value: 'hello' })
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## 内部启动顺序
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
open()
|
|
55
|
+
-> ensureBrowserd()
|
|
56
|
+
-> browserd.startPluginServer()
|
|
57
|
+
-> browserd.launchChromeWithProfile()
|
|
58
|
+
-> browserd.waitForExtensionHello()
|
|
59
|
+
-> 成功后返回 extension mode
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
这里 `background/offscreen` 不是用户启动的,是 Chrome 加载扩展后自动执行的。
|
|
63
|
+
|
|
64
|
+
## 扩展内部流程
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
Chrome 启动扩展 background
|
|
68
|
+
-> background ensureOffscreen()
|
|
69
|
+
-> offscreen 建立 WS 长连接
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`background` 不再持有 WebSocket,只负责创建 offscreen 和执行命令。
|
|
73
|
+
|
|
74
|
+
## 命令路径
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
browserd 发送 command
|
|
78
|
+
-> offscreen 收到 command
|
|
79
|
+
-> offscreen chrome.runtime.sendMessage({ source:'offscreen-command', command })
|
|
80
|
+
-> background handleCommand()
|
|
81
|
+
-> background 直接调用 chrome.tabs / chrome.cookies / chrome.scripting
|
|
82
|
+
或 sendToContent(tabId, ...)
|
|
83
|
+
-> background 返回结果给 offscreen
|
|
84
|
+
-> offscreen 回 response 给 browserd
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## open() 完成条件
|
|
88
|
+
|
|
89
|
+
所以插件运行不是独立步骤,它被包含在 `open()` 的握手里。
|
|
90
|
+
|
|
91
|
+
`open({ routeMode:'plugin' })` 的完成条件必须是:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
Chrome 已启动
|
|
95
|
+
WebPlater 已加载
|
|
96
|
+
offscreen 已连接当前 browserd 的 :17321
|
|
97
|
+
browserd 已收到 hello
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
没收到 hello,就不能返回 extension mode。
|
|
101
|
+
|
|
102
|
+
这就是"browser 技能打开浏览器,然后使用插件运行"的完整闭环。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*{box-sizing:border-box}body{margin:0;padding:0;font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:13px;color:#333;background:#f5f5f5}#app{width:440px;min-height:300px;padding:16px}header h1{margin:0 0 4px;font-size:16px}.status{margin:0 0 12px;font-size:12px;color:#888}section{background:#fff;border-radius:8px;padding:12px;margin-bottom:12px;box-shadow:0 1px 3px #0000000f}section h2{font-size:13px;margin:0 0 10px;color:#666}.row{display:flex;gap:8px;flex-wrap:wrap}button{padding:6px 12px;border:1px solid #d9d9d9;border-radius:4px;background:#fff;cursor:pointer;font-size:12px}button:hover{border-color:#40a9ff;color:#1890ff}input[type=text],textarea{width:100%;padding:6px 8px;margin-bottom:8px;border:1px solid #d9d9d9;border-radius:4px;font-family:monospace;font-size:12px}textarea{resize:vertical}.inline{display:flex;align-items:center;gap:6px;font-size:12px;color:#666;margin-top:6px}#result{background:#f6f8fa;border:1px solid #e1e4e8;border-radius:4px;padding:10px;max-height:280px;overflow:auto;font-size:11px;line-height:1.5;white-space:pre-wrap;word-break:break-all}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var background=(function(){"use strict";var A,B;function V(n){return n==null||typeof n=="function"?{main:n}:n}const W="offscreen.html",O=15e3,H=3e5,X=new Set(["evaluate","waitForFunction"]),Y=V(()=>{console.log("[WebPlater] background service worker started");let n=null,f=!1;async function u(t,e){const r=()=>re(e.tabId);switch(t){case"listTabs":return d();case"newTab":return g(String(e.url??""));case"switchTab":return m(M(e.tabId));case"reuseTab":return k(String(e.url??""),e.urlMatch!=null?new RegExp(String(e.urlMatch)):void 0);case"closeTab":return h(M(e.tabId));case"goto":return o(await r(),String(e.url??""));case"goBack":return b(await r());case"goForward":return i(await r());case"reload":return l(await r());case"evaluate":return $(await r(),String(e.source??""),e.args,e.frameId);case"listFrames":{const a=await r();return(await chrome.webNavigation.getAllFrames({tabId:a})||[]).map(s=>({frameId:s.frameId,url:s.url,parentFrameId:s.parentFrameId}))}case"listDownloads":return j(Number(e.limit??20));case"getDownload":return z(Number(e.id));case"waitForDownload":return L({filenameRegex:e.filenameRegex!=null?String(e.filenameRegex):void 0,sinceMs:e.sinceMs!=null?Number(e.sinceMs):void 0,timeoutMs:e.timeoutMs!=null?Number(e.timeoutMs):void 0,intervalMs:e.intervalMs!=null?Number(e.intervalMs):void 0});case"status":return P(await r());case"waitForLoadState":return E(await r());case"clickAt":return c(await r(),"clickAt",{x:Number(e.x),y:Number(e.y),button:e.button,clickCount:e.clickCount,frameId:e.frameId});case"clickByText":return c(await r(),"clickByText",{text:e.text,exact:e.exact,index:e.index,offsetX:e.offsetX,offsetY:e.offsetY,frameId:e.frameId});case"locateVisibleText":return c(await r(),"locateVisibleText",{text:e.text,exact:e.exact,index:e.index,frameId:e.frameId});case"operateSequence":return G(await r(),Array.isArray(e.steps)?e.steps:[]);case"click":return c(await r(),"click",{selector:e.selector,x:e.x,y:e.y});case"fill":return c(await r(),"fill",{selector:e.selector,value:e.value});case"type":return c(await r(),"type",{selector:e.selector,value:e.value,delay:e.delay});case"press":return c(await r(),"press",{selector:e.selector,key:e.key});case"hover":return c(await r(),"hover",{selector:e.selector,x:e.x,y:e.y});case"focus":return c(await r(),"focus",{selector:e.selector});case"mouseMove":return c(await r(),"mouseMove",{x:e.x,y:e.y});case"check":return c(await r(),"check",{selector:e.selector});case"uncheck":return c(await r(),"uncheck",{selector:e.selector});case"selectOption":return c(await r(),"selectOption",{selector:e.selector,value:e.value});case"waitForSelector":return c(await r(),"waitForSelector",{selector:e.selector,timeout:e.timeout});case"innerHTML":return c(await r(),"innerHTML",{selector:e.selector});case"innerText":return c(await r(),"innerText",{selector:e.selector});case"textContent":return c(await r(),"textContent",{selector:e.selector});case"getAttribute":return c(await r(),"getAttribute",{selector:e.selector,name:e.name});case"inputValue":return c(await r(),"inputValue",{selector:e.selector});case"boundingBox":return c(await r(),"boundingBox",{selector:e.selector});case"count":return c(await r(),"count",{selector:e.selector});case"setInputFiles":return c(await r(),"setInputFiles",{selector:e.selector,files:e.files});case"getLocalStorage":return c(await r(),"getLocalStorage",{keys:e.keys});case"setLocalStorage":return c(await r(),"setLocalStorage",{items:e.items});case"removeLocalStorage":return c(await r(),"removeLocalStorage",{keys:e.keys});case"clearLocalStorage":return c(await r(),"clearLocalStorage",{});case"dblclick":return c(await r(),"dblclick",{selector:e.selector});case"dragTo":return c(await r(),"dragTo",{source:e.source,target:e.target});case"waitForFunction":return c(await r(),"waitForFunction",{source:e.source,timeout:e.timeout,args:e.args});case"waitForURL":return c(await r(),"waitForURL",{url:e.url,timeout:e.timeout});case"waitForTimeout":return c(await r(),"waitForTimeout",{ms:e.ms});case"setDialogHandler":return c(await r(),"setDialogHandler",{handler:e.handler});case"snapshot":return c(await r(),"snapshot",{rootSelector:e.rootSelector,depth:e.depth,interactiveOnly:e.interactiveOnly,chunkId:e.chunkId,chunkSize:e.chunkSize,refresh:e.refresh});case"screenshot":return Q(await r());case"getCookies":return Z(e);case"setCookies":return ee(e);case"clearCookies":return te(e);case"enableCapture":return ie(String(e.script??""));case"disableCapture":return ae();default:throw new Error(`Unknown method: ${t}`)}}async function d(){return{tabs:(await chrome.tabs.query({})).filter(e=>e.id!=null).map(e=>({id:e.id,url:e.url??"",title:e.title??"",active:!!e.active,current:e.id===n}))}}async function g(t){const e=await chrome.tabs.create({url:t||"about:blank",active:!1});if(!e.id)throw new Error("createTab: no tab id");if(n=e.id,t&&t!=="about:blank"){await p(e.id,t);const r=await chrome.tabs.get(e.id);return{ok:!0,tabId:e.id,url:r.url??t}}return{ok:!0,tabId:e.id,url:e.url??t}}async function m(t){return await chrome.tabs.get(t),n=t,await chrome.tabs.update(t,{active:!0}),{ok:!0,tabId:t}}async function k(t,e){const r=await chrome.tabs.query({}),a=e?r.find(s=>s.id!=null&&e.test(s.url??"")):r.find(s=>s.id!=null&&(s.url??"")===t);if(a&&a.id!=null)return await m(a.id),{ok:!0,reused:!0,tabId:a.id,url:a.url??t};const w=await g(t);return{ok:!0,reused:!1,tabId:w.tabId,url:w.url??t}}async function h(t){return await chrome.tabs.remove(t),n===t&&(n=null),{ok:!0}}async function o(t,e){if(!e)throw new Error("goto requires url");await chrome.tabs.update(t,{url:e}),n=t,await p(t,e);const r=await chrome.tabs.get(t);return{ok:!0,tabId:t,url:r.url??e}}async function b(t){return await chrome.tabs.goBack(t),n=t,{ok:!0,tabId:t}}async function i(t){return await chrome.tabs.goForward(t),n=t,{ok:!0,tabId:t}}async function l(t){return await chrome.tabs.reload(t),n=t,{ok:!0,tabId:t}}async function P(t){const e=await chrome.tabs.get(t);n=t;let r="unknown",a=0;try{const w=await c(t,"status",{});r=(w==null?void 0:w.readyState)??"unknown",a=(w==null?void 0:w.textLength)??0}catch{}return{ok:!0,url:e.url??"",title:e.title??"",readyState:r,textLength:a}}async function E(t,e="complete"){const a=["loading","interactive","complete"].includes(e)?e:"complete",w=Date.now()+O;let s=!1;const v=Date.now()+5e3;for(;Date.now()<v&&Date.now()<w;){try{const y=await chrome.tabs.get(t);if(y.status==="loading"){s=!0;break}if(y.status==="complete"&&y.url&&y.url!=="about:blank"){s=!0;break}}catch{throw new Error("waitForLoadState: tab lost")}await D(80)}for(;Date.now()<w;){try{const I=(await chrome.tabs.get(t)).status??"complete";if(a==="loading")return{ok:!0,tabId:t,status:I};if(I==="complete")return{ok:!0,tabId:t,status:"complete"}}catch{throw new Error("waitForLoadState: tab lost")}await D(150)}throw new Error(`waitForLoadState timeout: ${e}`)}async function Q(t){var w;n=t;const e=await chrome.tabs.get(t);if(e.windowId==null)throw new Error(`screenshot failed: tab ${t} has no windowId`);if((((w=(await chrome.tabs.query({windowId:e.windowId,active:!0}))[0])==null?void 0:w.id)??null)!==t)throw new Error("screenshot in extension mode only supports the active visible tab; call operate(ph, { action: 'activate' }) and make sure the tab is visible before screenshot");try{const s=await chrome.tabs.captureVisibleTab(e.windowId,{format:"png"});return{ok:!0,tabId:t,format:"png",dataUrl:s}}catch(s){throw new Error(`screenshot failed: ${s instanceof Error?s.message:String(s)}`)}}async function Z(t){const e=t.url?String(t.url):void 0,r=t.domain?String(t.domain):void 0,a={};return e&&(a.url=e),r&&(a.domain=r),{ok:!0,cookies:(await chrome.cookies.getAll(a)).map(s=>({name:s.name,value:s.value,domain:s.domain,path:s.path,secure:s.secure,httpOnly:s.httpOnly,sameSite:s.sameSite,expirationDate:s.expirationDate}))}}async function ee(t){const e=t.cookies??[];for(const r of e){const a={url:String(r.url??""),name:String(r.name??""),value:String(r.value??"")};r.domain&&(a.domain=String(r.domain)),r.path&&(a.path=String(r.path)),r.secure!=null&&(a.secure=!!r.secure),r.httpOnly!=null&&(a.httpOnly=!!r.httpOnly),await chrome.cookies.set(a)}return{ok:!0,count:e.length}}async function te(t){const e=t.url?String(t.url):void 0,r=t.name?String(t.name):void 0;if(e)return{ok:!0,removed:await chrome.cookies.remove({url:e,name:r??""})!=null};const a=t.domain?String(t.domain):void 0;if(a){const w=await chrome.cookies.getAll({domain:a});let s=0;for(const v of w){const y=v.secure?"https":"http";await chrome.cookies.remove({url:`${y}://${v.domain.replace(/^\./,"")}${v.path}`,name:v.name})&&s++}return{ok:!0,count:s}}return{ok:!1,error:"clearCookies requires url or domain"}}function M(t){const e=Number(t);if(!Number.isFinite(e))throw new Error("tabId must be a number");return e}function D(t){return new Promise(e=>setTimeout(e,t))}async function p(t,e,r=5e3){const a=Date.now()+r;for(;Date.now()<a;){try{const w=await chrome.tabs.get(t);if((!e||e==="about:blank"||w.url&&w.url!=="about:blank"&&w.url!=="")&&(w.status==="loading"||w.status==="complete"))return}catch{throw new Error("waitForNavigationStarted: tab lost")}await D(80)}}async function re(t){if(t!=null)return M(t);if(n!=null)try{return await chrome.tabs.get(n),n}catch{n=null}throw new Error("no target tab: pass tabId explicitly (e.g. from newTab/switchTab)")}const U="bee-capture",ne="capture.js";async function oe(){if(!f){try{await chrome.scripting.unregisterScript({id:U})}catch{}await chrome.scripting.registerContentScripts([{id:U,matches:["<all_urls>"],js:[ne],runAt:"document_start",allFrames:!0}]),f=!0,console.log("[WebPlater] capture script registered (ISOLATED, document_start)")}}async function q(t){await chrome.storage.local.set({bee_capture_enabled:t})}async function ie(t){return await oe(),await q(!0),console.log("[WebPlater] enableCapture: storage.bee_capture_enabled=true"),{ok:!0}}async function ae(){return await q(!1),console.log("[WebPlater] disableCapture: storage.bee_capture_enabled=false"),{ok:!0}}let T=null;async function ce(){try{return(await chrome.runtime.getContexts({contextTypes:[chrome.runtime.ContextType.OFFSCREEN_DOCUMENT]})).length>0}catch{return await chrome.offscreen.hasDocument()}}async function C(){if(!await ce()){if(T){await T;return}T=chrome.offscreen.createDocument({url:W,reasons:[chrome.offscreen.Reason.WORKERS],justification:"Hold a persistent WebSocket to the local host bridge (browserd :17321)."}),await T,T=null,console.log("[WebPlater] offscreen document created")}}chrome.runtime.onMessage.addListener((t,e,r)=>(t==null?void 0:t.source)==="offscreen-command"?(u(t.method,t.params??{}).then(a=>r({ok:!0,result:a})).catch(a=>r({ok:!1,error:a instanceof Error?a.message:String(a)})),!0):(t==null?void 0:t.source)==="bee-plugin-popup"?t.method==="reconnect"?(C().then(()=>r({ok:!0,result:{offscreen:!0}})).catch(a=>r({ok:!1,error:a instanceof Error?a.message:String(a)})),!0):(u(t.method,t.params??{}).then(a=>r({ok:!0,result:a})).catch(a=>r({ok:!1,error:a instanceof Error?a.message:String(a)})),!0):!1),chrome.runtime.onStartup.addListener(()=>{C()}),chrome.runtime.onInstalled.addListener(()=>{C()}),C()});function F(n){return{id:n.id,filename:n.filename||"",url:n.url||(n.finalUrl??""),state:n.state,bytesReceived:n.bytesReceived,totalBytes:n.totalBytes,exists:n.exists}}async function j(n=20){return{downloads:(await chrome.downloads.search({orderBy:["-startTime"],limit:n})||[]).map(F)}}async function z(n){const f=await chrome.downloads.search({id:n});return{download:f&&f[0]?F(f[0]):null}}async function L(n){const f=n.timeoutMs??6e4,u=n.intervalMs??2e3,d=n.filenameRegex?new RegExp(n.filenameRegex):null,g=n.sinceMs??0,m=Date.now()+f;for(;Date.now()<m;){await new Promise(i=>setTimeout(i,u));const h=(await chrome.downloads.search({orderBy:["-startTime"],limit:20})||[]).filter(i=>{if(i.startTime==null)return!1;const l=Date.parse(i.startTime);return!(isNaN(l)||l<g||d&&!d.test(i.filename||""))}),o=h.find(i=>i.state==="complete"&&i.exists);if(o)return{download:F(o),reason:"complete"};h.find(i=>i.state==="in_progress")}return{download:null,reason:"timeout"}}async function G(n,f){var g,m,k;const u={},d=[];for(let h=0;h<f.length;h++){const o=f[h]||{},b=String(o.action||"");try{if(b==="locateVisibleText"){const i=await c(n,"locateVisibleText",{text:o.text,exact:o.exact,index:o.index,frameId:o.frameId});if(d.push({step:h,action:b,ok:i==null?void 0:i.ok,count:(g=i==null?void 0:i.matches)==null?void 0:g.length}),o.saveAs&&((m=i==null?void 0:i.matches)!=null&&m.length)&&(u[String(o.saveAs)]=i.matches[0]),!(i!=null&&i.ok)||!((k=i==null?void 0:i.matches)!=null&&k.length))return{ok:!1,results:d,error:`step ${h} locateVisibleText: text not visible: ${o.text}`}}else if(b==="clickAt"){let i=o.x!=null?Number(o.x):void 0,l=o.y!=null?Number(o.y):void 0;if(o.from&&u[String(o.from)]){const E=u[String(o.from)];i=Math.round(E.centerX+Number(o.dx??0)),l=Math.round(E.centerY+Number(o.dy??0))}if(i==null||l==null)throw new Error(`step ${h} clickAt: need x,y or from`);const P=await c(n,"clickAt",{x:i,y:l,button:o.button,clickCount:o.clickCount,frameId:o.frameId});d.push({step:h,action:b,ok:!0,x:i,y:l})}else if(b==="clickByText"){const i=o.index!=null?Number(o.index):0,l=await c(n,"clickByText",{text:o.text,exact:o.exact,index:i,offsetX:o.offsetX,offsetY:o.offsetY,frameId:o.frameId});if(!(l!=null&&l.ok))return{ok:!1,results:d,error:`step ${h} clickByText: ${(l==null?void 0:l.error)||"text not visible: "+o.text}`};d.push({step:h,action:b,ok:!0,x:l.x,y:l.y}),o.saveAs&&(l!=null&&l.match)&&(u[String(o.saveAs)]=l.match)}else if(b==="waitForTimeout")await new Promise(i=>setTimeout(i,Number(o.ms??0))),d.push({step:h,action:b,ok:!0});else if(b==="waitForDownload"){const i=o.sinceMs!=null?Number(o.sinceMs):Date.now(),l=await L({filenameRegex:o.filenameRegex!=null?String(o.filenameRegex):void 0,sinceMs:i,timeoutMs:Number(o.timeout??6e4),intervalMs:Number(o.intervalMs??2e3)});if(d.push({step:h,action:b,ok:!!l.download,download:l.download,reason:l.reason}),!l.download)return{ok:!1,results:d,error:`step ${h} waitForDownload: timeout`}}else if(b==="evaluate"){const i=await $(n,String(o.source??""),o.args,typeof o.frameId=="number"?o.frameId:void 0);d.push({step:h,action:b,ok:!0,result:i})}else throw new Error(`step ${h} unknown action: ${b}`)}catch(i){return{ok:!1,results:d,error:`step ${h} (${b}) failed: ${(i==null?void 0:i.message)||i}`}}}return{ok:!0,results:d}}const K="content-scripts/content.js";function _(n){return/Receiving end does not exist|Could not establish connection/i.test(n)}async function R(n,f){const u={tabId:n};typeof f=="number"&&(u.frameIds=[f]),await chrome.scripting.executeScript({target:u,files:[K]})}function x(n,f,u){const d=X.has(f)?H:O;return new Promise((g,m)=>{const k=setTimeout(()=>{m(new Error(`content script timeout: ${f}`))},d),h=typeof(u==null?void 0:u.frameId)=="number"?u.frameId:void 0,o=h!==void 0?{frameId:h}:void 0;chrome.tabs.sendMessage(n,{source:"bee-plugin",method:f,params:u??{}},o,b=>{if(clearTimeout(k),chrome.runtime.lastError){m(new Error(chrome.runtime.lastError.message));return}if(b&&typeof b=="object"&&b.ok===!1){m(new Error(b.error??"content error"));return}g(b)})})}async function c(n,f,u){const d=typeof(u==null?void 0:u.frameId)=="number"?u.frameId:void 0;try{await x(n,"ping",{frameId:d})}catch(g){const m=String((g==null?void 0:g.message)||g);if(!_(m))throw g;await R(n,d),await x(n,"ping",{frameId:d})}try{return await x(n,f,u)}catch(g){const m=String((g==null?void 0:g.message)||g);if(!_(m))throw g;return await R(n,d),await x(n,f,u)}}async function $(n,f,u,d){if(!f)throw new Error("evaluate requires source");const g={tabId:n};typeof d=="number"&&(g.frameIds=[d]);const[m]=await chrome.scripting.executeScript({target:g,world:"MAIN",func:async(k,h)=>{const o=(0,eval)(`(${k})`);return typeof o=="function"?await o(h):o},args:[f,u??null]});return m==null?void 0:m.result}function se(){}((B=(A=globalThis.browser)==null?void 0:A.runtime)==null?void 0:B.id)==null?globalThis.chrome:globalThis.browser;function S(n,...f){}const J={debug:(...n)=>S(console.debug,...n),log:(...n)=>S(console.log,...n),warn:(...n)=>S(console.warn,...n),error:(...n)=>S(console.error,...n)};let N;try{N=Y.main(),N instanceof Promise&&console.warn("The background's main() function return a promise, but it must be synchronous")}catch(n){throw J.error("The background crashed on startup!"),n}return N})();
|
|
2
|
+
background;
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 捕获脚本本体(webplater 自带,等价 bee 的 capture-inject.ts captureInjectJS)。
|
|
3
|
+
*
|
|
4
|
+
* 行为:鼠标悬浮蓝色高亮 + Ctrl+C 复制 BeeCapture 到剪贴板。
|
|
5
|
+
* 由 background 用 chrome.scripting.registerContentScripts(world:'MAIN',
|
|
6
|
+
* runAt:'document_start') 注册,等价 CDP Page.addScriptToEvaluateOnNewDocument
|
|
7
|
+
* ——每个文档加载(导航/刷新/新 tab)都自动执行,document_start 即注入,持久存在。
|
|
8
|
+
*
|
|
9
|
+
* installed/enabled 标志位做幂等与开关控制。enabled 由 background 控制
|
|
10
|
+
* (开启捕获时 background 再注入一次把 enabled 置 true)。
|
|
11
|
+
*
|
|
12
|
+
* ⚠️ 此脚本是 bee/packages/.../capture-inject.ts 的 captureInjectJS 的独立副本。
|
|
13
|
+
* webplater 与 bee 非 monorepo,逻辑需手动保持一致(两处改动要同步)。
|
|
14
|
+
*/
|
|
15
|
+
(function () {
|
|
16
|
+
if (window.__bee_capture_installed) return;
|
|
17
|
+
|
|
18
|
+
// enabled 状态存 chrome.storage.local(background enable/disable 写入)。
|
|
19
|
+
// 脚本跑在 ISOLATED world,可直接读 storage + 监听变化,所有 tab(含新 tab)状态一致。
|
|
20
|
+
var enabled = false;
|
|
21
|
+
try { chrome.storage.local.get(['bee_capture_enabled'], function (r) {
|
|
22
|
+
enabled = !!r && r.bee_capture_enabled;
|
|
23
|
+
}); } catch (e) {}
|
|
24
|
+
try { chrome.storage.onChanged.addListener(function (changes, area) {
|
|
25
|
+
if (area === 'local' && changes.bee_capture_enabled) {
|
|
26
|
+
enabled = !!changes.bee_capture_enabled.newValue;
|
|
27
|
+
}
|
|
28
|
+
}); } catch (e) {}
|
|
29
|
+
|
|
30
|
+
var BEE_MIME = 'web application/vnd.bee.capture+json';
|
|
31
|
+
|
|
32
|
+
function escapeHtml(s) {
|
|
33
|
+
return String(s)
|
|
34
|
+
.replace(/&/g, '&')
|
|
35
|
+
.replace(/"/g, '"')
|
|
36
|
+
.replace(/</g, '<')
|
|
37
|
+
.replace(/>/g, '>');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function buildLabel(el) {
|
|
41
|
+
var text = (el.textContent || '').trim().replace(/\s+/g, ' ').slice(0, 40);
|
|
42
|
+
if (text) return text;
|
|
43
|
+
var tag = el.tagName ? el.tagName.toLowerCase() : 'element';
|
|
44
|
+
var parts = [tag];
|
|
45
|
+
if (el.id) parts.push('#' + el.id);
|
|
46
|
+
if (el.className && typeof el.className === 'string') {
|
|
47
|
+
var classes = el.className.split(/\s+/).filter(Boolean);
|
|
48
|
+
if (classes.length) parts.push('.' + classes.join('.'));
|
|
49
|
+
}
|
|
50
|
+
return 'DOM: ' + parts.join('');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function buildStableSelector(el) {
|
|
54
|
+
var path = [];
|
|
55
|
+
var node = el;
|
|
56
|
+
var MAX_DEPTH = 15;
|
|
57
|
+
var depth = 0;
|
|
58
|
+
while (node && node.nodeType === 1 && node.tagName && depth < MAX_DEPTH) {
|
|
59
|
+
var tag = node.tagName.toLowerCase();
|
|
60
|
+
if (tag === 'html') break;
|
|
61
|
+
if (tag === 'body') { path.unshift('body'); break; }
|
|
62
|
+
var parent = node.parentElement;
|
|
63
|
+
if (!parent) { path.unshift(tag); break; }
|
|
64
|
+
var index = 1;
|
|
65
|
+
var sibling = parent.firstElementChild;
|
|
66
|
+
while (sibling && sibling !== node) {
|
|
67
|
+
sibling = sibling.nextElementSibling;
|
|
68
|
+
index++;
|
|
69
|
+
}
|
|
70
|
+
if (parent.id && /^[A-Za-z][\w-]*$/.test(parent.id)) {
|
|
71
|
+
path.unshift(tag + ':nth-child(' + index + ')');
|
|
72
|
+
path.unshift('#' + parent.id);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
path.unshift(tag + ':nth-child(' + index + ')');
|
|
76
|
+
node = parent;
|
|
77
|
+
depth++;
|
|
78
|
+
}
|
|
79
|
+
return path.join(' > ');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function inferImplicitRole(el, tagLower) {
|
|
83
|
+
if (tagLower === 'a' && el.getAttribute('href')) return 'link';
|
|
84
|
+
if (tagLower === 'a') return 'generic';
|
|
85
|
+
var directMap = {
|
|
86
|
+
button: 'button', nav: 'navigation', main: 'main', header: 'banner',
|
|
87
|
+
footer: 'contentinfo', aside: 'complementary', form: 'form', search: 'search',
|
|
88
|
+
ul: 'list', ol: 'list', li: 'listitem', table: 'table', tr: 'row', td: 'cell',
|
|
89
|
+
th: 'columnheader', img: 'image', figure: 'figure', dialog: 'dialog',
|
|
90
|
+
};
|
|
91
|
+
if (directMap[tagLower]) return directMap[tagLower];
|
|
92
|
+
if (/^h[1-6]$/.test(tagLower)) return 'heading';
|
|
93
|
+
if (tagLower === 'input') {
|
|
94
|
+
var inputType = (el.getAttribute('type') || 'text').toLowerCase();
|
|
95
|
+
if (inputType === 'button' || inputType === 'submit' || inputType === 'reset') return 'button';
|
|
96
|
+
if (inputType === 'checkbox') return 'checkbox';
|
|
97
|
+
if (inputType === 'radio') return 'radio';
|
|
98
|
+
if (inputType === 'range') return 'slider';
|
|
99
|
+
if (inputType === 'search') return 'searchbox';
|
|
100
|
+
return 'textbox';
|
|
101
|
+
}
|
|
102
|
+
if (tagLower === 'textarea') return 'textbox';
|
|
103
|
+
if (tagLower === 'select') return 'listbox';
|
|
104
|
+
return '';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function buildA11yInfo(el) {
|
|
108
|
+
var role = el.getAttribute('role') || '';
|
|
109
|
+
var ariaLabel = el.getAttribute('aria-label') || '';
|
|
110
|
+
var ariaLabelledBy = el.getAttribute('aria-labelledby') || '';
|
|
111
|
+
var ariaDescribedBy = el.getAttribute('aria-describedby') || '';
|
|
112
|
+
var headingLevel = 0;
|
|
113
|
+
var tagLower = (el.tagName || '').toLowerCase();
|
|
114
|
+
var hMatch = tagLower.match(/^h(\d)$/);
|
|
115
|
+
if (hMatch) headingLevel = parseInt(hMatch[1], 10);
|
|
116
|
+
if (!headingLevel && role === 'heading') {
|
|
117
|
+
var ariaLevel = el.getAttribute('aria-level');
|
|
118
|
+
if (ariaLevel) headingLevel = parseInt(ariaLevel, 10);
|
|
119
|
+
}
|
|
120
|
+
if (!role) role = inferImplicitRole(el, tagLower);
|
|
121
|
+
var name = ariaLabel || ((el.textContent || '').trim().replace(/\s+/g, ' ').slice(0, 40));
|
|
122
|
+
return {
|
|
123
|
+
role: role, name: name, ariaLabel: ariaLabel,
|
|
124
|
+
ariaLabelledBy: ariaLabelledBy, ariaDescribedBy: ariaDescribedBy,
|
|
125
|
+
headingLevel: headingLevel || undefined,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function buildParentContext(el) {
|
|
130
|
+
var contexts = [];
|
|
131
|
+
var node = el.parentElement;
|
|
132
|
+
var depth = 0;
|
|
133
|
+
var semClassRe = /(?:^|[\s_-])(nav|menu|header|footer|sidebar|content|main|body|article|post|list|item|card|product|detail|search|login|user|cart|banner|hero|modal|dialog|popup|tab|panel|section|category|breadcrumb|pagination|comment|reply|form|register|checkout|profile|setting)(?:[\s_-]|$)/i;
|
|
134
|
+
while (node && depth < 8) {
|
|
135
|
+
var role = node.getAttribute && node.getAttribute('role');
|
|
136
|
+
var nodeTag = (node.tagName || '').toLowerCase();
|
|
137
|
+
var nodeClass = (typeof node.className === 'string' ? node.className : '');
|
|
138
|
+
var nodeText = (node.textContent || '').trim().replace(/\s+/g, ' ').slice(0, 30);
|
|
139
|
+
var hasSemanticClass = semClassRe.test(nodeClass);
|
|
140
|
+
var isSemantic = role || /^h[1-6]$/.test(nodeTag) ||
|
|
141
|
+
['nav', 'main', 'header', 'footer', 'section', 'article', 'aside', 'form', 'dialog', 'ul', 'ol', 'table'].indexOf(nodeTag) >= 0 ||
|
|
142
|
+
node.id || hasSemanticClass;
|
|
143
|
+
if (isSemantic) {
|
|
144
|
+
contexts.push({
|
|
145
|
+
tag: nodeTag, role: role || inferImplicitRole(node, nodeTag),
|
|
146
|
+
id: node.id || '', className: nodeClass, text: nodeText,
|
|
147
|
+
});
|
|
148
|
+
if (contexts.length >= 3) break;
|
|
149
|
+
}
|
|
150
|
+
node = node.parentElement;
|
|
151
|
+
depth++;
|
|
152
|
+
}
|
|
153
|
+
return contexts;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function buildCapture(el) {
|
|
157
|
+
var tag = el.tagName ? el.tagName.toLowerCase() : '';
|
|
158
|
+
var attrs = {};
|
|
159
|
+
if (el.attributes) {
|
|
160
|
+
for (var i = 0; i < el.attributes.length; i++) {
|
|
161
|
+
var a = el.attributes[i];
|
|
162
|
+
attrs[a.name] = a.value;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
var selector = el.id ? '#' + el.id : tag;
|
|
166
|
+
if (!el.id && el.className && typeof el.className === 'string') {
|
|
167
|
+
var classes = el.className.split(/\s+/).filter(Boolean);
|
|
168
|
+
if (classes.length) selector += '.' + classes.join('.');
|
|
169
|
+
}
|
|
170
|
+
var text = (el.textContent || '').trim().slice(0, 200);
|
|
171
|
+
return {
|
|
172
|
+
v: 1, source: 'browser', kind: 'dom-element',
|
|
173
|
+
label: buildLabel(el),
|
|
174
|
+
preview: text ? text.slice(0, 80) : undefined,
|
|
175
|
+
data: {
|
|
176
|
+
tag: tag, id: el.id || '',
|
|
177
|
+
className: typeof el.className === 'string' ? el.className : '',
|
|
178
|
+
text: text, selector: selector,
|
|
179
|
+
stableSelector: buildStableSelector(el),
|
|
180
|
+
attributes: attrs, a11y: buildA11yInfo(el),
|
|
181
|
+
parentContext: buildParentContext(el),
|
|
182
|
+
url: location.href, title: document.title,
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function encodeCaptureHtml(capture, refId) {
|
|
188
|
+
var dataStr = encodeURIComponent(JSON.stringify(capture.data));
|
|
189
|
+
var previewAttr = capture.preview
|
|
190
|
+
? ' data-bee-preview="' + escapeHtml(capture.preview) + '"'
|
|
191
|
+
: '';
|
|
192
|
+
return '<a data-bee-capture="' + escapeHtml(refId) + '"' +
|
|
193
|
+
' data-bee-source="' + escapeHtml(capture.source) + '"' +
|
|
194
|
+
' data-bee-kind="' + escapeHtml(capture.kind) + '"' +
|
|
195
|
+
' data-bee-label="' + escapeHtml(capture.label) + '"' +
|
|
196
|
+
' data-bee-data="' + escapeHtml(dataStr) + '"' +
|
|
197
|
+
previewAttr + '>' + escapeHtml(capture.label) + '</a>';
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function execCommandCopy(html) {
|
|
201
|
+
try {
|
|
202
|
+
var container = document.createElement('div');
|
|
203
|
+
container.setAttribute('contenteditable', 'true');
|
|
204
|
+
container.style.cssText = 'position:fixed;left:-9999px;top:0;opacity:0;';
|
|
205
|
+
container.innerHTML = html;
|
|
206
|
+
document.body.appendChild(container);
|
|
207
|
+
var range = document.createRange();
|
|
208
|
+
range.selectNodeContents(container);
|
|
209
|
+
var sel = window.getSelection();
|
|
210
|
+
sel.removeAllRanges();
|
|
211
|
+
sel.addRange(range);
|
|
212
|
+
var ok = document.execCommand('copy');
|
|
213
|
+
sel.removeAllRanges();
|
|
214
|
+
document.body.removeChild(container);
|
|
215
|
+
return ok;
|
|
216
|
+
} catch (e) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function writeCaptureToClipboard(capture) {
|
|
222
|
+
var refId = 'browser_' + Date.now() + '_' + Math.random().toString(36).slice(2, 8);
|
|
223
|
+
var html = encodeCaptureHtml(capture, refId);
|
|
224
|
+
var plainText = JSON.stringify(capture, null, 2);
|
|
225
|
+
var jsonStr = JSON.stringify(capture);
|
|
226
|
+
if (navigator.clipboard && navigator.clipboard.write && window.ClipboardItem) {
|
|
227
|
+
try {
|
|
228
|
+
var items = {
|
|
229
|
+
'text/html': new Blob([html], { type: 'text/html' }),
|
|
230
|
+
'text/plain': new Blob([plainText], { type: 'text/plain' }),
|
|
231
|
+
};
|
|
232
|
+
try { items[BEE_MIME] = new Blob([jsonStr], { type: BEE_MIME }); } catch (e) { }
|
|
233
|
+
return navigator.clipboard.write([new ClipboardItem(items)]).then(function () {
|
|
234
|
+
return 'clipboard.write';
|
|
235
|
+
}, function () { return execCommandCopy(html); }).catch(function () {
|
|
236
|
+
return execCommandCopy(html);
|
|
237
|
+
});
|
|
238
|
+
} catch (e) { }
|
|
239
|
+
}
|
|
240
|
+
var result = execCommandCopy(html);
|
|
241
|
+
if (result) return Promise.resolve('execCommand');
|
|
242
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
243
|
+
return navigator.clipboard.writeText(html);
|
|
244
|
+
}
|
|
245
|
+
return Promise.reject(new Error('Clipboard API not available'));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function install() {
|
|
249
|
+
if (window.__bee_capture_installed) return;
|
|
250
|
+
|
|
251
|
+
var highlight = document.createElement('div');
|
|
252
|
+
highlight.id = '__bee_highlight';
|
|
253
|
+
highlight.style.cssText = 'position:fixed;pointer-events:none;z-index:2147483647;border:2px solid #3b82f6;background:rgba(59,130,246,0.1);display:none;transition:all 0.08s ease;';
|
|
254
|
+
document.documentElement.appendChild(highlight);
|
|
255
|
+
|
|
256
|
+
var currentTarget = null;
|
|
257
|
+
|
|
258
|
+
document.addEventListener('mouseover', function (e) {
|
|
259
|
+
if (!enabled) return;
|
|
260
|
+
if (e.target === highlight) return;
|
|
261
|
+
currentTarget = e.target;
|
|
262
|
+
var r = e.target.getBoundingClientRect();
|
|
263
|
+
highlight.style.left = r.left + 'px';
|
|
264
|
+
highlight.style.top = r.top + 'px';
|
|
265
|
+
highlight.style.width = r.width + 'px';
|
|
266
|
+
highlight.style.height = r.height + 'px';
|
|
267
|
+
highlight.style.display = 'block';
|
|
268
|
+
}, true);
|
|
269
|
+
|
|
270
|
+
document.addEventListener('mouseout', function (e) {
|
|
271
|
+
if (e.target === currentTarget) {
|
|
272
|
+
highlight.style.display = 'none';
|
|
273
|
+
currentTarget = null;
|
|
274
|
+
}
|
|
275
|
+
}, true);
|
|
276
|
+
|
|
277
|
+
document.addEventListener('keydown', function (e) {
|
|
278
|
+
if (!enabled) return;
|
|
279
|
+
if ((e.ctrlKey || e.metaKey) && e.key === 'c') {
|
|
280
|
+
var el = currentTarget || document.activeElement;
|
|
281
|
+
if (!el || el === document.body || el === document.documentElement) return;
|
|
282
|
+
var capture = buildCapture(el);
|
|
283
|
+
if (!capture) return;
|
|
284
|
+
e.preventDefault();
|
|
285
|
+
e.stopPropagation();
|
|
286
|
+
writeCaptureToClipboard(capture).then(function (method) {
|
|
287
|
+
highlight.style.border = '2px solid #22c55e';
|
|
288
|
+
highlight.style.background = 'rgba(34,197,94,0.2)';
|
|
289
|
+
setTimeout(function () {
|
|
290
|
+
highlight.style.border = '2px solid #3b82f6';
|
|
291
|
+
highlight.style.background = 'rgba(59,130,246,0.1)';
|
|
292
|
+
}, 300);
|
|
293
|
+
}).catch(function () { });
|
|
294
|
+
}
|
|
295
|
+
}, true);
|
|
296
|
+
|
|
297
|
+
window.addEventListener('scroll', function () {
|
|
298
|
+
highlight.style.display = 'none';
|
|
299
|
+
currentTarget = null;
|
|
300
|
+
}, true);
|
|
301
|
+
|
|
302
|
+
window.__bee_capture_installed = true;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (document.documentElement && document.body) {
|
|
306
|
+
install();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
document.addEventListener('DOMContentLoaded', install, { once: true });
|
|
310
|
+
})();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const e of document.querySelectorAll('link[rel="modulepreload"]'))n(e);new MutationObserver(e=>{for(const r of e)if(r.type==="childList")for(const o of r.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&n(o)}).observe(document,{childList:!0,subtree:!0});function s(e){const r={};return e.integrity&&(r.integrity=e.integrity),e.referrerPolicy&&(r.referrerPolicy=e.referrerPolicy),e.crossOrigin==="use-credentials"?r.credentials="include":e.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function n(e){if(e.ep)return;e.ep=!0;const r=s(e);fetch(e.href,r)}})();try{}catch(i){console.error("[wxt] Failed to initialize plugins",i)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual_wxt-html-plugins-DPbbfBKe.js";const l="ws://127.0.0.1:17321",p=1e3,E=2e4;let e=null,s=null,c=null;function d(){(e==null?void 0:e.readyState)===WebSocket.CONNECTING||(e==null?void 0:e.readyState)===WebSocket.OPEN||(e=new WebSocket(l),e.addEventListener("open",()=>{s&&(clearTimeout(s),s=null),console.log("[WebPlater/offscreen] connected to host",l),i({type:"hello",name:"bee-web-plugin"}),y()}),e.addEventListener("message",async t=>{let n;try{n=JSON.parse(String(t.data))}catch{console.error("[WebPlater/offscreen] invalid JSON from host",t.data);return}if(!(!n||n.type!=="command"||typeof n.id!="number"))try{const r=await S(n.id,n.method,n.params??{});u(n.id,{ok:!0,result:r})}catch(r){u(n.id,{ok:!1,error:r instanceof Error?r.message:String(r)})}}),e.addEventListener("close",()=>{console.log("[WebPlater/offscreen] disconnected, reconnecting..."),e=null,f(),b()}),e.addEventListener("error",()=>{e==null||e.close()}))}function i(t){(e==null?void 0:e.readyState)===WebSocket.OPEN&&e.send(JSON.stringify(t))}function u(t,n){const r={id:t,type:"response",...n};i(r)}function S(t,n,r){return new Promise((m,a)=>{chrome.runtime.sendMessage({source:"offscreen-command",id:t,method:n,params:r},g=>{if(chrome.runtime.lastError){a(new Error(chrome.runtime.lastError.message));return}const o=g;if(o&&typeof o=="object"&&o.ok===!1){a(new Error(o.error??"background error"));return}m(o==null?void 0:o.result)})})}function y(){f(),c=setInterval(()=>{i({type:"ping",time:Date.now()})},E)}function f(){c&&(clearInterval(c),c=null)}function b(){s||(s=setTimeout(()=>{s=null,d()},p))}d();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual_wxt-html-plugins-DPbbfBKe.js";const n=document.getElementById("result"),o=document.getElementById("status");function t(e){n.textContent=typeof e=="string"?e:JSON.stringify(e,null,2)}async function s(){return new Promise(e=>{chrome.runtime.sendMessage({source:"bee-plugin-popup",method:"listTabs"},r=>{if(chrome.runtime.lastError){e(!1);return}e(!!r)})})}document.getElementById("btn-tabs").addEventListener("click",async()=>{n.textContent="loading...",chrome.runtime.sendMessage({source:"bee-plugin-popup",method:"listTabs"},e=>{if(chrome.runtime.lastError){t(chrome.runtime.lastError.message);return}t(e)})});document.getElementById("btn-status").addEventListener("click",async()=>{n.textContent="loading...",chrome.runtime.sendMessage({source:"bee-plugin-popup",method:"status"},e=>{if(chrome.runtime.lastError){t(chrome.runtime.lastError.message);return}t(e)})});document.getElementById("btn-reconnect").addEventListener("click",()=>{chrome.runtime.sendMessage({source:"bee-plugin-popup",method:"reconnect"},e=>{if(chrome.runtime.lastError){t(chrome.runtime.lastError.message);return}t(e!=null&&e.ok?"offscreen ensured; WS (re)connects automatically":e)})});(async()=>{const e=await s();o.textContent=e?"background responsive":"background no response"})();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
var content=(function(){"use strict";var On=Object.defineProperty;var Rn=(H,A,F)=>A in H?On(H,A,{enumerable:!0,configurable:!0,writable:!0,value:F}):H[A]=F;var _=(H,A,F)=>Rn(H,typeof A!="symbol"?A+"":A,F);var Oe,Re;function H(e){return e}var A=Object.prototype.toString;function F(e){return typeof e=="function"||A.call(e)==="[object Function]"}function Ve(e){var t=Number(e);return isNaN(t)?0:t===0||!isFinite(t)?t:(t>0?1:-1)*Math.floor(Math.abs(t))}var Ke=Math.pow(2,53)-1;function De(e){var t=Ve(e);return Math.min(Math.max(t,0),Ke)}function w(e,t){var n=Array,i=Object(e);if(e==null)throw new TypeError("Array.from requires an array-like object - not null or undefined");for(var r=De(i.length),o=F(n)?Object(new n(r)):new Array(r),s=0,u;s<r;)u=i[s],o[s]=u,s+=1;return o.length=r,o}function V(e){"@babel/helpers - typeof";return V=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},V(e)}function je(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function qe(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,pe(i.key),i)}}function Ue(e,t,n){return t&&qe(e.prototype,t),Object.defineProperty(e,"prototype",{writable:!1}),e}function We(e,t,n){return t=pe(t),t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function pe(e){var t=Be(e,"string");return V(t)=="symbol"?t:t+""}function Be(e,t){if(V(e)!="object"||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var i=n.call(e,t);if(V(i)!="object")return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}var Ge=(function(){function e(){var t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:[];je(this,e),We(this,"items",void 0),this.items=t}return Ue(e,[{key:"add",value:function(n){return this.has(n)===!1&&this.items.push(n),this}},{key:"clear",value:function(){this.items=[]}},{key:"delete",value:function(n){var i=this.items.length;return this.items=this.items.filter(function(r){return r!==n}),i!==this.items.length}},{key:"forEach",value:function(n){var i=this;this.items.forEach(function(r){n(r,r,i)})}},{key:"has",value:function(n){return this.items.indexOf(n)!==-1}},{key:"size",get:function(){return this.items.length}}])})();const ze=typeof Set>"u"?Set:Ge;function v(e){var t;return(t=e.localName)!==null&&t!==void 0?t:e.tagName.toLowerCase()}var Ye={article:"article",aside:"complementary",button:"button",datalist:"listbox",dd:"definition",details:"group",dialog:"dialog",dt:"term",fieldset:"group",figure:"figure",form:"form",footer:"contentinfo",h1:"heading",h2:"heading",h3:"heading",h4:"heading",h5:"heading",h6:"heading",header:"banner",hr:"separator",html:"document",legend:"legend",li:"listitem",math:"math",main:"main",menu:"list",nav:"navigation",ol:"list",optgroup:"group",option:"option",output:"status",progress:"progressbar",section:"region",summary:"button",table:"table",tbody:"rowgroup",textarea:"textbox",tfoot:"rowgroup",td:"cell",th:"columnheader",thead:"rowgroup",tr:"row",ul:"list"},Xe={caption:new Set(["aria-label","aria-labelledby"]),code:new Set(["aria-label","aria-labelledby"]),deletion:new Set(["aria-label","aria-labelledby"]),emphasis:new Set(["aria-label","aria-labelledby"]),generic:new Set(["aria-label","aria-labelledby","aria-roledescription"]),insertion:new Set(["aria-label","aria-labelledby"]),none:new Set(["aria-label","aria-labelledby"]),paragraph:new Set(["aria-label","aria-labelledby"]),presentation:new Set(["aria-label","aria-labelledby"]),strong:new Set(["aria-label","aria-labelledby"]),subscript:new Set(["aria-label","aria-labelledby"]),superscript:new Set(["aria-label","aria-labelledby"])};function Je(e,t){return["aria-atomic","aria-busy","aria-controls","aria-current","aria-description","aria-describedby","aria-details","aria-dropeffect","aria-flowto","aria-grabbed","aria-hidden","aria-keyshortcuts","aria-label","aria-labelledby","aria-live","aria-owns","aria-relevant","aria-roledescription"].some(function(n){var i;return e.hasAttribute(n)&&!((i=Xe[t])!==null&&i!==void 0&&i.has(n))})}function ge(e,t){return Je(e,t)}function ve(e){var t=Ze(e);if(t===null||oe.indexOf(t)!==-1){var n=Qe(e);if(oe.indexOf(t||"")===-1||ge(e,n||""))return n}return t}function Qe(e){var t=Ye[v(e)];if(t!==void 0)return t;switch(v(e)){case"a":case"area":case"link":if(e.hasAttribute("href"))return"link";break;case"img":return e.getAttribute("alt")===""&&!ge(e,"img")?"presentation":"img";case"input":{var n=e,i=n.type;switch(i){case"button":case"image":case"reset":case"submit":return"button";case"checkbox":case"radio":return i;case"range":return"slider";case"email":case"tel":case"text":case"url":return e.hasAttribute("list")?"combobox":"textbox";case"search":return e.hasAttribute("list")?"combobox":"searchbox";case"number":return"spinbutton";default:return null}}case"select":return e.hasAttribute("multiple")||e.size>1?"listbox":"combobox"}return null}function Ze(e){var t=e.getAttribute("role");if(t!==null){var n=t.trim().split(" ")[0];if(n.length>0)return n}return null}var oe=["presentation","none"];function h(e){return e!==null&&e.nodeType===e.ELEMENT_NODE}function ye(e){return h(e)&&v(e)==="caption"}function G(e){return h(e)&&v(e)==="input"}function et(e){return h(e)&&v(e)==="optgroup"}function tt(e){return h(e)&&v(e)==="select"}function nt(e){return h(e)&&v(e)==="table"}function rt(e){return h(e)&&v(e)==="textarea"}function it(e){var t=e.ownerDocument===null?e:e.ownerDocument,n=t.defaultView;if(n===null)throw new TypeError("no window available");return n}function ot(e){return h(e)&&v(e)==="fieldset"}function at(e){return h(e)&&v(e)==="legend"}function st(e){return h(e)&&v(e)==="slot"}function ut(e){return h(e)&&e.ownerSVGElement!==void 0}function lt(e){return h(e)&&v(e)==="svg"}function ct(e){return ut(e)&&v(e)==="title"}function ae(e,t){if(h(e)&&e.hasAttribute(t)){var n=e.getAttribute(t).split(" "),i=e.getRootNode?e.getRootNode():e.ownerDocument;return n.map(function(r){return i.getElementById(r)}).filter(function(r){return r!==null})}return[]}function N(e,t){return h(e)?t.indexOf(ve(e))!==-1:!1}function ft(e){return e.trim().replace(/\s\s+/g," ")}function dt(e,t){if(!h(e))return!1;if(e.hasAttribute("hidden")||e.getAttribute("aria-hidden")==="true")return!0;var n=t(e);return n.getPropertyValue("display")==="none"||n.getPropertyValue("visibility")==="hidden"}function ht(e){return N(e,["button","combobox","listbox","textbox"])||we(e,"range")}function we(e,t){if(!h(e))return!1;switch(t){case"range":return N(e,["meter","progressbar","scrollbar","slider","spinbutton"]);default:throw new TypeError("No knowledge about abstract role '".concat(t,"'. This is likely a bug :("))}}function Ee(e,t){var n=w(e.querySelectorAll(t));return ae(e,"aria-owns").forEach(function(i){n.push.apply(n,w(i.querySelectorAll(t)))}),n}function bt(e){return tt(e)?e.selectedOptions||Ee(e,"[selected]"):Ee(e,'[aria-selected="true"]')}function mt(e){return N(e,oe)}function pt(e){return ye(e)}function gt(e){return N(e,["button","cell","checkbox","columnheader","gridcell","heading","label","legend","link","menuitem","menuitemcheckbox","menuitemradio","option","radio","row","rowheader","switch","tab","tooltip","treeitem"])}function vt(e){return!1}function yt(e){return G(e)||rt(e)?e.value:e.textContent||""}function Se(e){var t=e.getPropertyValue("content");return/^["'].*["']$/.test(t)?t.slice(1,-1):""}function ke(e){var t=v(e);return t==="button"||t==="input"&&e.getAttribute("type")!=="hidden"||t==="meter"||t==="output"||t==="progress"||t==="select"||t==="textarea"}function Te(e){if(ke(e))return e;var t=null;return e.childNodes.forEach(function(n){if(t===null&&h(n)){var i=Te(n);i!==null&&(t=i)}}),t}function wt(e){if(e.control!==void 0)return e.control;var t=e.getAttribute("for");return t!==null?e.ownerDocument.getElementById(t):Te(e)}function Et(e){var t=e.labels;if(t===null)return t;if(t!==void 0)return w(t);if(!ke(e))return null;var n=e.ownerDocument;return w(n.querySelectorAll("label")).filter(function(i){return wt(i)===e})}function St(e){var t=e.assignedNodes();return t.length===0?w(e.childNodes):t}function kt(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=new ze,i=typeof Map>"u"?void 0:new Map,r=it(e),o=t.compute,s=o===void 0?"name":o,u=t.computedStyleSupportsPseudoElements,l=u===void 0?t.getComputedStyle!==void 0:u,f=t.getComputedStyle,c=f===void 0?r.getComputedStyle.bind(r):f,p=t.hidden,y=p===void 0?!1:p,W=function(b,m){if(m!==void 0)throw new Error("use uncachedGetComputedStyle directly for pseudo elements");if(i===void 0)return c(b);var k=i.get(b);if(k)return k;var T=c(b,m);return i.set(b,T),T};function E(a,b){var m="";if(h(a)&&l){var k=c(a,"::before"),T=Se(k);m="".concat(T," ").concat(m)}var I=st(a)?St(a):w(a.childNodes).concat(ae(a,"aria-owns"));if(I.forEach(function(x){var R=C(x,{isEmbeddedInLabel:b.isEmbeddedInLabel,isReferenced:!1,recursion:!0}),L=h(x)?W(x).getPropertyValue("display"):"inline",B=L!=="inline"?" ":"";m+="".concat(B).concat(R).concat(B)}),h(a)&&l){var P=c(a,"::after"),O=Se(P);m="".concat(m," ").concat(O)}return m.trim()}function S(a,b){var m=a.getAttributeNode(b);return m!==null&&!n.has(m)&&m.value.trim()!==""?(n.add(m),m.value):null}function ie(a){return h(a)?S(a,"title"):null}function $(a){if(!h(a))return null;if(ot(a)){n.add(a);for(var b=w(a.childNodes),m=0;m<b.length;m+=1){var k=b[m];if(at(k))return C(k,{isEmbeddedInLabel:!1,isReferenced:!1,recursion:!1})}}else if(nt(a)){n.add(a);for(var T=w(a.childNodes),I=0;I<T.length;I+=1){var P=T[I];if(ye(P))return C(P,{isEmbeddedInLabel:!1,isReferenced:!1,recursion:!1})}}else if(lt(a)){n.add(a);for(var O=w(a.childNodes),x=0;x<O.length;x+=1){var R=O[x];if(ct(R))return R.textContent}return null}else if(v(a)==="img"||v(a)==="area"){var L=S(a,"alt");if(L!==null)return L}else if(et(a)){var B=S(a,"label");if(B!==null)return B}if(G(a)&&(a.type==="button"||a.type==="submit"||a.type==="reset")){var _e=S(a,"value");if(_e!==null)return _e;if(a.type==="submit")return"Submit";if(a.type==="reset")return"Reset"}var be=Et(a);if(be!==null&&be.length!==0)return n.add(a),w(be).map(function(me){return C(me,{isEmbeddedInLabel:!0,isReferenced:!1,recursion:!0})}).filter(function(me){return me.length>0}).join(" ");if(G(a)&&a.type==="image"){var He=S(a,"alt");if(He!==null)return He;var Fe=S(a,"title");return Fe!==null?Fe:"Submit Query"}if(N(a,["button"])){var $e=E(a,{isEmbeddedInLabel:!1});if($e!=="")return $e}return null}function C(a,b){if(n.has(a))return"";if(!y&&dt(a,W)&&!b.isReferenced)return n.add(a),"";var m=h(a)?a.getAttributeNode("aria-labelledby"):null,k=m!==null&&!n.has(m)?ae(a,"aria-labelledby"):[];if(s==="name"&&!b.isReferenced&&k.length>0)return n.add(m),k.map(function(L){return C(L,{isEmbeddedInLabel:b.isEmbeddedInLabel,isReferenced:!0,recursion:!1})}).join(" ");var T=b.recursion&&ht(a)&&s==="name";if(!T){var I=(h(a)&&a.getAttribute("aria-label")||"").trim();if(I!==""&&s==="name")return n.add(a),I;if(!mt(a)){var P=$(a);if(P!==null)return n.add(a),P}}if(N(a,["menu"]))return n.add(a),"";if(T||b.isEmbeddedInLabel||b.isReferenced){if(N(a,["combobox","listbox"])){n.add(a);var O=bt(a);return O.length===0?G(a)?a.value:"":w(O).map(function(L){return C(L,{isEmbeddedInLabel:b.isEmbeddedInLabel,isReferenced:!1,recursion:!0})}).join(" ")}if(we(a,"range"))return n.add(a),a.hasAttribute("aria-valuetext")?a.getAttribute("aria-valuetext"):a.hasAttribute("aria-valuenow")?a.getAttribute("aria-valuenow"):a.getAttribute("value")||"";if(N(a,["textbox"]))return n.add(a),yt(a)}if(gt(a)||h(a)&&b.isReferenced||pt(a)||vt()){var x=E(a,{isEmbeddedInLabel:b.isEmbeddedInLabel});if(x!=="")return n.add(a),x}if(a.nodeType===a.TEXT_NODE)return n.add(a),a.textContent||"";if(b.recursion)return n.add(a),E(a,{isEmbeddedInLabel:b.isEmbeddedInLabel});var R=ie(a);return R!==null?(n.add(a),R):(n.add(a),"")}return ft(C(e,{isEmbeddedInLabel:!1,isReferenced:s==="description",recursion:!1}))}function Tt(e){return N(e,["caption","code","deletion","emphasis","generic","insertion","none","paragraph","presentation","strong","subscript","superscript"])}function xt(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return Tt(e)?"":kt(e,t)}const z=new Map;let se=0;function At(){document.querySelectorAll("[data-bee-ref]").forEach(e=>e.removeAttribute("data-bee-ref")),z.clear(),se=0}function xe(e){const t=z.get(e);if(t&&document.contains(t))return t;const n=document.querySelector(`[data-bee-ref="${e}"]`);if(n)return z.set(e,n),n}const Nt={H1:1,H2:2,H3:3,H4:4,H5:5,H6:6};function It(e,t){var f;const n=[];(((f=e.hasAttribute)==null?void 0:f.call(e,"disabled"))||e.getAttribute("aria-disabled")==="true")&&n.push("disabled");const r=e.getAttribute("aria-checked");(t==="checkbox"||t==="radio"||t==="menuitemcheckbox"||t==="menuitemradio"||t==="switch"||t==="option"||r!=null)&&(r==="true"||e.checked===!0&&r==null?n.push("checked"):r==="mixed"&&n.push("checked=mixed"));const o=e.getAttribute("aria-expanded");o!=null&&n.push(o==="true"?"expanded":"expanded=false");const s=e.getAttribute("aria-pressed");s!=null&&n.push(s==="true"?"pressed":"pressed=false"),e.getAttribute("aria-selected")==="true"&&n.push("selected");const l=e.getAttribute("aria-invalid");if(l==="true"||l===""?n.push("invalid"):l==="grammar"?n.push("invalid=grammar"):l==="spelling"&&n.push("invalid=spelling"),t==="heading"){let c=Number(e.getAttribute("aria-level"));(!Number.isFinite(c)||c<1)&&(c=Nt[e.tagName]??0),c>0&&n.push(`level=${c}`)}return n}function Lt(e){if(e.getAttribute("aria-hidden")==="true")return!0;const t=e.style;return!!((t==null?void 0:t.display)==="none"||(t==null?void 0:t.visibility)==="hidden"||e.hasAttribute("hidden"))}const Mt=new Set(["button","link","textbox","checkbox","radio","switch","menuitem","menuitemcheckbox","menuitemradio","option","tab","heading","separator","slider","spinbutton","progressbar","img","alert","status","note","tooltip","scrollbar"]),Ct=new Set(["button","link","textbox","checkbox","radio","switch","menuitem","menuitemcheckbox","menuitemradio","option","tab","combobox","menu","menubar","listbox","treeitem","tree","slider","spinbutton","searchbox","gridcell","row","toolbar","tablist"]);function Pt(e){let t="";for(const n of Array.from(e.childNodes))n.nodeType===Node.TEXT_NODE&&(t+=(n.textContent||"")+" ");return t=t.replace(/\s+/g," ").trim(),t.length>200&&(t=t.slice(0,200)+"..."),t}function ue(e){const t=`e${++se}`;z.set(t,e);try{e.setAttribute("data-bee-ref",t)}catch{}return t}const Ot=new Set(["SCRIPT","STYLE","NOSCRIPT","TEMPLATE","LINK","META","TITLE","BASE","HEAD","COL","COLGROUP"]);function le(e,t,n=0){if(Lt(e)||Ot.has(e.tagName))return null;const i=t.depth!=null&&n>=t.depth,r=ve(e),o=xt(e).trim()||void 0;if(r){const u=It(e,r),l=ue(e);if(r==="textbox"){const c=e.value||"";return{role:r,name:o,attributes:u.length?u:void 0,ref:l,value:c||void 0}}if(Mt.has(r))return{role:r,name:o,attributes:u.length?u:void 0,ref:l};let f=[];if(!i)for(const c of Array.from(e.children)){const p=le(c,t,n+1);p&&f.push(p)}return f.length===0&&o?{role:r,name:o,attributes:u.length?u:void 0,ref:l}:{role:r,name:o,attributes:u.length?u:void 0,ref:l,children:f.length?f:void 0}}const s=Pt(e);if(!s){const u=[];if(!i)for(const l of Array.from(e.children)){const f=le(l,t,n+1);f&&u.push(f)}return u.length===1?u[0]:u.length>1?{role:"text",ref:ue(e),children:u}:null}return{role:"text",ref:ue(e),name:s}}function Rt(e){if(!e)return"";let t=e;return t.length>200&&(t=t.slice(0,200)+"..."),` "${t.replace(/"/g,'\\"')}"`}function Y(e,t){var u;const n=" ".repeat(t),i=[];let r=`${n}- ${e.role}`;if(e.name&&(r+=Rt(e.name)),(u=e.attributes)!=null&&u.length)for(const l of e.attributes)r+=` [${l}]`;r+=` [ref=${e.ref}]`;const o=e.children&&e.children.length>0,s=e.value!==void 0;if(o){r+=":",i.push(r);for(const l of e.children)i.push(Y(l,t+1))}else s&&(r+=`: ${e.value}`),i.push(r);return i.join(`
|
|
2
|
+
`)}function _t(e={}){At();const t=e.rootSelector&&document.querySelector(e.rootSelector)||document.body,n={depth:e.depth,interactiveOnly:e.interactiveOnly},i=[];for(const o of Array.from(t.children)){const s=le(o,n,0);s&&i.push(s)}let r;if(e.interactiveOnly){const o=[];for(const s of i)Ae(s,o);r=o.map(s=>Y(s,0)).join(`
|
|
3
|
+
`)}else i.length===1?r=Y(i[0],0):i.length>1?r=i.map(o=>Y(o,0)).join(`
|
|
4
|
+
`):r="";return{yaml:r,refs:se}}function Ae(e,t){if(Ht(e.role)){t.push(e);return}if(e.children)for(const n of e.children)Ae(n,t)}function Ht(e){return Ct.has(e)||e==="textbox"}function d(e){return Promise.resolve().then(()=>e()).then(t=>t).catch(t=>({ok:!1,error:t instanceof Error?t.message:String(t)}))}function g(e){return Ft(e)}function Ft(e){const t=e.indexOf(">>");let n=e,i="";t>=0&&(n=e.slice(0,t),i=e.slice(t+2).trim().toLowerCase());let r;if(n.startsWith("aria-ref=")){const u=n.slice(9).trim();if(r=xe(u)??null,!r)throw new Error(`stale ref: ${u} (call snapshot first)`);if(!document.contains(r))throw new Error(`detached ref: ${u}`);return r}const o=Array.from(document.querySelectorAll(n));if(o.length===0)throw new Error(`element not found: ${n}`);let s;if(i==="last")s=o[o.length-1];else if(i.startsWith("nth(")&&i.endsWith(")")){const u=Number(i.slice(4,-1));if(!Number.isInteger(u))throw new Error(`invalid nth index: ${i}`);if(s=o[u],!s)throw new Error(`nth(${u}) out of range: ${n} has ${o.length} matches`)}else s=o[0];return s}function $t(e){const t=e.indexOf(">>"),n=t>=0?e.slice(0,t):e;if(n.startsWith("aria-ref=")){const i=n.slice(9).trim(),r=xe(i);return r&&document.contains(r)?1:0}return document.querySelectorAll(n).length}function K(e){const t=e.getBoundingClientRect(),n=window.innerHeight||document.documentElement.clientHeight,i=window.innerWidth||document.documentElement.clientWidth,r=t.left+t.width/2,o=t.top+t.height/2;return o>=0&&o<=n&&r>=0&&r<=i}function Vt(){var e,t;return{ok:!0,url:location.href,title:document.title,readyState:document.readyState,textLength:((t=(e=document.body)==null?void 0:e.innerText)==null?void 0:t.length)??0}}const Kt={left:0,middle:1,right:2};function X(e){return new Promise(t=>setTimeout(t,e))}function ce(e){return Kt[e]??0}function D(e,t,n,i){return{bubbles:!0,cancelable:!0,composed:!0,clientX:e,clientY:t,button:n,buttons:i,pointerType:"mouse",isPrimary:!0,view:window}}function M(e,t){return document.elementFromPoint(e,t)||document.body}function j(e){const t=e.getBoundingClientRect();return{x:t.left+t.width/2,y:t.top+t.height/2}}function Ne(e,t){const n=D(e,t,0,0),i=M(e,t);i.dispatchEvent(new PointerEvent("pointermove",n)),i.dispatchEvent(new MouseEvent("mousemove",n))}function Dt(e,t){const n=D(e,t,0,0),i=M(e,t);i.dispatchEvent(new PointerEvent("pointerover",n)),i.dispatchEvent(new MouseEvent("mouseover",n)),i.dispatchEvent(new PointerEvent("pointerenter",n)),i.dispatchEvent(new MouseEvent("mouseenter",n)),i.dispatchEvent(new PointerEvent("pointermove",n)),i.dispatchEvent(new MouseEvent("mousemove",n))}function Ie(e,t,n){var s;const i=ce(n),r=D(e,t,i,1<<i),o=M(e,t);o.dispatchEvent(new PointerEvent("pointerover",r)),o.dispatchEvent(new MouseEvent("mouseover",r)),o.dispatchEvent(new PointerEvent("pointerenter",r)),o.dispatchEvent(new MouseEvent("mouseenter",r)),o.dispatchEvent(new PointerEvent("pointerdown",r)),o.dispatchEvent(new MouseEvent("mousedown",r)),(s=o.focus)==null||s.call(o)}function Le(e,t,n){const i=ce(n),r=1<<i,o=M(e,t),s=D(e,t,i,r),u=D(e,t,i,0);o.dispatchEvent(new PointerEvent("pointerup",s)),o.dispatchEvent(new MouseEvent("mouseup",s)),o.dispatchEvent(new MouseEvent("click",s)),o.dispatchEvent(new PointerEvent("pointerout",u)),o.dispatchEvent(new MouseEvent("mouseout",u)),o.dispatchEvent(new PointerEvent("pointerleave",u)),o.dispatchEvent(new MouseEvent("mouseleave",u))}async function J(e,t,n={}){const i=n.button??"left",r=n.delay??0,o=n.clickCount??1;for(let s=0;s<o;s++)Ie(e,t,i),r>0&&await X(r),Le(e,t,i),s<o-1&&r>0&&await X(r);if(o>=2){const s=ce(i),u=o,l=M(e,t),f={bubbles:!0,cancelable:!0,clientX:e,clientY:t,button:s,buttons:0,detail:u,view:window};l.dispatchEvent(new MouseEvent("dblclick",f))}}function Q(){return document.activeElement||document.body}function jt(e,t){var n,i;if(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement){const r=e instanceof HTMLTextAreaElement?HTMLTextAreaElement.prototype:HTMLInputElement.prototype;(i=(n=Object.getOwnPropertyDescriptor(r,"value"))==null?void 0:n.set)==null||i.call(e,e.value+t)}else if(e.isContentEditable)try{document.execCommand("insertText",!1,t)}catch{}}function qt(e){const t=Q();t.dispatchEvent(new KeyboardEvent("keydown",{key:e,bubbles:!0,cancelable:!0})),t.dispatchEvent(new KeyboardEvent("keypress",{key:e,bubbles:!0,cancelable:!0}))}function Ut(e){Q().dispatchEvent(new KeyboardEvent("keyup",{key:e,bubbles:!0,cancelable:!0}))}async function Wt(e){qt(e),await X(0),Ut(e)}async function Bt(e,t=50){const n=Q();n&&typeof n.focus=="function"&&n.focus();for(const i of e){const r=Q();r.dispatchEvent(new KeyboardEvent("keydown",{key:i,bubbles:!0,cancelable:!0})),r.dispatchEvent(new KeyboardEvent("keypress",{key:i,bubbles:!0,cancelable:!0})),jt(r,i),r.dispatchEvent(new InputEvent("input",{bubbles:!0,cancelable:!0,data:i,inputType:"insertText"})),r.dispatchEvent(new KeyboardEvent("keyup",{key:i,bubbles:!0,cancelable:!0})),t>0&&await X(t)}}async function Gt(e,t,n){let i,r;if(t!=null&&n!=null)i=Number(t),r=Number(n);else{const o=g(e);if(!K(o))throw new Error("ELEMENT_OUT_OF_VIEWPORT: "+e+" (scroll via ScrollController first)");const s=j(o);i=s.x,r=s.y}return await J(i,r,{button:"left"}),{ok:!0,selector:e,x:i,y:r}}function zt(e,t){var r,o;const n=g(e);n.focus();const i=n instanceof HTMLTextAreaElement?HTMLTextAreaElement.prototype:HTMLInputElement.prototype;return(o=(r=Object.getOwnPropertyDescriptor(i,"value"))==null?void 0:r.set)==null||o.call(n,t),n.dispatchEvent(new InputEvent("input",{bubbles:!0,data:t,inputType:"insertText"})),n.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0,selector:e,value:t}}async function Yt(e,t,n=50){const i=g(e);return(i instanceof HTMLInputElement||i instanceof HTMLTextAreaElement||i.isContentEditable)&&(i.focus(),(i instanceof HTMLInputElement||i instanceof HTMLTextAreaElement)&&(i.value="")),await Bt(t,n),(i instanceof HTMLInputElement||i instanceof HTMLTextAreaElement)&&i.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0,selector:e,value:t}}async function Xt(e,t){var i;const n=g(e);if(n.focus(),await Wt(t),t==="Enter"&&n instanceof HTMLInputElement){const r=n.form;r&&((i=r.requestSubmit)==null||i.call(r))}return{ok:!0,selector:e,key:t}}function Jt(e,t,n){let i,r;if(t!=null&&n!=null)i=Number(t),r=Number(n);else{const o=g(e);if(!K(o))throw new Error("ELEMENT_OUT_OF_VIEWPORT: "+e+" (scroll via ScrollController first)");const s=j(o);i=s.x,r=s.y}return Dt(i,r),{ok:!0,selector:e,x:i,y:r}}function Qt(e){const t=g(e);if(!K(t))throw new Error("ELEMENT_OUT_OF_VIEWPORT: "+e+" (scroll via ScrollController first)");return t.focus(),{ok:!0,selector:e}}function Zt(e,t){return Ne(Number(e),Number(t)),{ok:!0,x:Number(e),y:Number(t)}}function Me(e,t=!0){const n=g(e);return n.checked!==t&&(n.checked=t,n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))),{ok:!0,selector:e,checked:n.checked}}function en(e){return Me(e,!1)}function tn(e,t){const n=g(e),i=Array.from(n.options).find(r=>r.value===t||r.text===t);if(!i)throw new Error(`selectOption: option not found for value="${t}"`);return n.value=i.value,n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0})),{ok:!0,selector:e,value:n.value}}async function nn(e,t=3e4){const n=Date.now()+t;for(;Date.now()<n;){const i=document.querySelector(e);if(i)return{ok:!0,selector:e,visible:!0,inViewport:K(i)};await new Promise(r=>setTimeout(r,100))}throw new Error(`waitForSelector timeout (${t}ms): ${e}`)}function rn(e){const t=g(e);return{ok:!0,selector:e,value:t.innerHTML}}function on(e){const t=g(e);return{ok:!0,selector:e,value:t.innerText}}function an(e){const t=g(e);return{ok:!0,selector:e,value:t.textContent??""}}function sn(e,t){const n=g(e);return{ok:!0,selector:e,name:t,value:n.getAttribute(t)}}function un(e){const t=g(e);return{ok:!0,selector:e,value:t.value}}function ln(e){const n=g(e).getBoundingClientRect();return{ok:!0,selector:e,x:Math.round(n.x),y:Math.round(n.y),width:Math.round(n.width),height:Math.round(n.height)}}function cn(e){return{ok:!0,selector:e,count:$t(e)}}function fn(e,t){var p;const n=g(e);if(n.tagName!=="INPUT"||n.type!=="file")throw new Error(`not a file input: ${e} (tag=${n.tagName} type=${n.type})`);const i=new DataTransfer,r=[];let o=0;for(const y of t){const W=y.data.split(",").pop()??y.data,E=atob(W),S=new Uint8Array(E.length);for(let $=0;$<E.length;$++)S[$]=E.charCodeAt($);o+=S.length;const ie=new File([S],y.name,{type:y.mime||"application/octet-stream"});if(y.webkitRelativePath)try{Object.defineProperty(ie,"webkitRelativePath",{configurable:!0,value:y.webkitRelativePath})}catch{}i.items.add(ie),r.push(y.name)}const s=i.files.length,u=Object.getPrototypeOf(n),l=Object.getOwnPropertyDescriptor(u,"files");l!=null&&l.set?l.set.call(n,i.files):n.files=i.files,n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}));const f=((p=n.files)==null?void 0:p.length)??0,c=n.files?Array.from(n.files).map(y=>y.name):[];return{ok:s>0,selector:e,requested:t.length,built:s,onInput:f,names:r,onInputNames:c,totalBytes:o,note:f===0&&s>0?"files constructed and set, but input.files now empty — 框架可能已接收并清空,看页面 UI 是否出现文件":void 0}}function dn(e){const t={},n=e&&e.length>0?e:Object.keys(localStorage);for(const i of n)t[i]=localStorage.getItem(i);return{ok:!0,storage:t}}function hn(e){let t=0;for(const[n,i]of Object.entries(e))localStorage.setItem(n,i),t++;return{ok:!0,count:t}}function bn(e){const t=e&&e.length>0?e:Object.keys(localStorage);for(const n of t)localStorage.removeItem(n);return{ok:!0,count:t.length}}function mn(){return localStorage.clear(),{ok:!0}}async function pn(e){const t=g(e);if(!K(t))throw new Error("ELEMENT_OUT_OF_VIEWPORT: "+e+" (scroll via ScrollController first)");const{x:n,y:i}=j(t);return await J(n,i,{clickCount:2}),{ok:!0,selector:e}}function gn(e,t){const n=g(e),i=g(t),r=j(n),o=j(i);Ie(r.x,r.y,"left");const s=10;for(let l=1;l<=s;l++){const f=r.x+(o.x-r.x)*l/s,c=r.y+(o.y-r.y)*l/s;Ne(f,c)}Le(o.x,o.y,"left");const u=new DataTransfer;for(const l of["dragstart","drag","dragenter","dragover","drop","dragend"]){const f=new DragEvent(l,{bubbles:!0,cancelable:!0,dataTransfer:u,clientX:0,clientY:0});(l==="drop"||l==="dragover"||l==="dragenter"?i:n).dispatchEvent(f)}return{ok:!0,source:e,target:t}}async function vn(e,t=3e4,n){if(!e)throw new Error("waitForFunction requires source");const i=(0,eval)(`(${e})`),r=Date.now()+t;for(;Date.now()<r;){let o=!1,s;try{s=i(n),o=!!s}catch{}if(o)return{ok:!0,source:e,value:s};await new Promise(u=>setTimeout(u,100))}throw new Error(`waitForFunction timeout (${t}ms)`)}async function yn(e,t=3e4){const n=Date.now()+t;let i=null;try{i=new RegExp(e)}catch{i=null}for(;Date.now()<n;){const r=location.href;if(i&&i.test(r)||!i&&r.includes(e))return{ok:!0,url:r};await new Promise(o=>setTimeout(o,100))}throw new Error(`waitForURL timeout (${t}ms): ${e}`)}async function wn(e){return await new Promise(t=>setTimeout(t,Math.min(e,12e4))),{ok:!0,ms:e}}let Z=null;function En(e){return e?(Z=(0,eval)(`(${e})`),{ok:!0,enabled:!0}):(Z=null,{ok:!0,enabled:!1})}["alert","confirm","prompt"].forEach(e=>{Object.defineProperty(window,e,{configurable:!0,value(t){return Z&&Z(e,String(t??""))==="dismiss"?e==="prompt"?null:!1:e==="alert"?void 0:e==="confirm"?!0:""}})});const Sn=1e4;let q=null;function kn(e){return[e.rootSelector??"",String(e.depth??""),String(e.interactiveOnly??!1)].join("|")}function Tn(e,t){const n=[];let i=[],r=0;for(const o of e)r+o.length>t&&i.length>0&&(n.push(i),i=[],r=0),i.push(o),r+=o.length+1;return i.length>0&&n.push(i),n}function xn(e){const t=kn(e),n=e.chunkSize&&e.chunkSize>0?e.chunkSize:Sn;if(!q||q.key!==t||q.chunkSize!==n||e.refresh){const l=_t({rootSelector:e.rootSelector,depth:e.depth,interactiveOnly:e.interactiveOnly}),f=l.yaml.length>0?l.yaml.split(`
|
|
5
|
+
`):[],c=Tn(f,n);q={key:t,yaml:l.yaml,lines:f,chunkSize:n,chunkCount:c.length},Ce=c}const i=q,r=e.chunkId??0,o=Ce[r],s=o?o.join(`
|
|
6
|
+
`):"",u=r+1<i.chunkCount;return{ok:!0,yaml:s,chunkId:r,chunkCount:i.chunkCount,chunkSize:i.chunkSize,hasMore:u,totalChars:i.yaml.length,hint:u?`还有 ${i.chunkCount-r-1} 块,用 snapshot({chunkId: ${r+1}}) 续取`:void 0}}let Ce=[];const An={matches:["<all_urls>"],allFrames:!0,runAt:"document_idle",main(){chrome.runtime.onMessage.addListener((e,t,n)=>{if((e==null?void 0:e.source)!=="bee-plugin")return;const i=e.method,r=e.params??{};let o;switch(i){case"ping":o=Promise.resolve({ok:!0,route:"extension-content",url:location.href,readyState:document.readyState});break;case"status":o=d(()=>Vt());break;case"click":o=d(()=>Gt(String(r.selector??""),typeof r.x=="number"?r.x:void 0,typeof r.y=="number"?r.y:void 0));break;case"fill":o=d(()=>zt(String(r.selector??""),String(r.value??"")));break;case"type":o=d(()=>Yt(String(r.selector??""),String(r.value??""),Number(r.delay??50)));break;case"press":o=d(()=>Xt(String(r.selector??""),String(r.key??"")));break;case"hover":o=d(()=>Jt(String(r.selector??""),typeof r.x=="number"?r.x:void 0,typeof r.y=="number"?r.y:void 0));break;case"focus":o=d(()=>Qt(String(r.selector??"")));break;case"mouseMove":o=d(()=>Zt(Number(r.x??0),Number(r.y??0)));break;case"check":o=d(()=>Me(String(r.selector??"")));break;case"uncheck":o=d(()=>en(String(r.selector??"")));break;case"selectOption":o=d(()=>tn(String(r.selector??""),String(r.value??"")));break;case"waitForSelector":o=d(()=>nn(String(r.selector??""),Number(r.timeout??3e4)));break;case"innerHTML":o=d(()=>rn(String(r.selector??"")));break;case"innerText":o=d(()=>on(String(r.selector??"")));break;case"textContent":o=d(()=>an(String(r.selector??"")));break;case"getAttribute":o=d(()=>sn(String(r.selector??""),String(r.name??"")));break;case"inputValue":o=d(()=>un(String(r.selector??"")));break;case"boundingBox":o=d(()=>ln(String(r.selector??"")));break;case"count":o=d(()=>cn(String(r.selector??"")));break;case"setInputFiles":o=d(()=>fn(String(r.selector??""),Array.isArray(r.files)?r.files:[]));break;case"getLocalStorage":o=d(()=>dn(Array.isArray(r.keys)?r.keys:void 0));break;case"setLocalStorage":o=d(()=>hn(r.items??{}));break;case"removeLocalStorage":o=d(()=>bn(Array.isArray(r.keys)?r.keys:void 0));break;case"clearLocalStorage":o=d(()=>mn());break;case"dblclick":o=d(()=>pn(String(r.selector??"")));break;case"dragTo":o=d(()=>gn(String(r.source??""),String(r.target??"")));break;case"waitForFunction":o=d(()=>vn(String(r.source??""),Number(r.timeout??3e4),r.args));break;case"waitForURL":o=d(()=>yn(String(r.url??""),Number(r.timeout??3e4)));break;case"waitForTimeout":o=d(()=>wn(Number(r.ms??1e3)));break;case"setDialogHandler":o=d(()=>En(r.handler==null?null:String(r.handler)));break;case"snapshot":o=d(()=>xn({rootSelector:r.rootSelector==null?void 0:String(r.rootSelector),depth:typeof r.depth=="number"?r.depth:void 0,interactiveOnly:r.interactiveOnly===!0,chunkId:typeof r.chunkId=="number"?r.chunkId:0,chunkSize:typeof r.chunkSize=="number"?r.chunkSize:void 0,refresh:r.refresh===!0}));break;case"locateVisibleText":o=d(()=>Pe({text:String(r.text??""),exact:r.exact===!0,index:typeof r.index=="number"?r.index:void 0}));break;case"clickAt":o=d(async()=>{const s=Number(r.x),u=Number(r.y);if(!Number.isFinite(s)||!Number.isFinite(u))throw new Error("clickAt: x/y must be finite");const l=M(s,u);return await J(s,u,{button:r.button||"left",clickCount:Number(r.clickCount??1)}),{ok:!0,x:s,y:u,route:"extension-content",trusted:!1,targetTag:l==null?void 0:l.tagName,targetText:((l==null?void 0:l.textContent)||"").trim().slice(0,40)}});break;case"clickByText":o=d(async()=>{const s=Pe({text:String(r.text??""),exact:r.exact===!0,index:typeof r.index=="number"?r.index:void 0});if(!s.matches||s.matches.length===0)throw new Error("clickByText: text not visible: "+r.text);const u=Math.max(0,Math.min(s.matches.length-1,Number(r.index??0))),l=s.matches[u],f=Math.round(l.centerX+Number(r.offsetX??0)),c=Math.round(l.centerY+Number(r.offsetY??0)),p=M(f,c);return await J(f,c,{button:r.button||"left",clickCount:Number(r.clickCount??1)}),{ok:!0,text:r.text,x:f,y:c,match:l,route:"extension-content",trusted:!1,targetTag:p==null?void 0:p.tagName,targetText:((p==null?void 0:p.textContent)||"").trim().slice(0,40)}});break;default:o=Promise.resolve({ok:!1,error:`unknown method: ${i}`})}return o.then(s=>n(s)),!0}),console.log("[WebPlater] content script loaded",location.href)}};function Pe(e){const{text:t,exact:n=!1}=e;typeof e.index=="number"&&e.index;const i=[],r=l=>{let f=l;for(;f&&f!==document.body;){const c=getComputedStyle(f);if(c.display==="none"||c.visibility==="hidden"||Number(c.opacity)===0)return!1;f=f.parentElement}return!0},o=document.createTreeWalker(document.body,NodeFilter.SHOW_TEXT,{acceptNode:l=>{const f=(l.nodeValue||"").trim();if(!f||!(n?f===t:f.includes(t)))return NodeFilter.FILTER_REJECT;const p=l.parentElement;return!p||!r(p)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT}}),s=window.innerHeight||document.documentElement.clientHeight,u=window.innerWidth||document.documentElement.clientWidth;for(;o.nextNode();){const l=o.currentNode,f=l.parentElement;if(!f)continue;let c=null;try{const E=document.createRange();E.selectNodeContents(l),c=E.getBoundingClientRect()}catch{c=f.getBoundingClientRect()}if(!c||c.width<=0||c.height<=0)continue;const p=c.x+c.width/2,y=c.y+c.height/2;y>=0&&y<=s&&p>=0&&p<=u&&i.push({text:(l.nodeValue||"").trim().slice(0,80),x:Math.round(c.x),y:Math.round(c.y),width:Math.round(c.width),height:Math.round(c.height),centerX:Math.round(p),centerY:Math.round(y),visible:!0})}return{ok:!0,matches:i}}const ee=((Re=(Oe=globalThis.browser)==null?void 0:Oe.runtime)==null?void 0:Re.id)==null?globalThis.chrome:globalThis.browser;function te(e,...t){}const Nn={debug:(...e)=>te(console.debug,...e),log:(...e)=>te(console.log,...e),warn:(...e)=>te(console.warn,...e),error:(...e)=>te(console.error,...e)},re=class re extends Event{constructor(t,n){super(re.EVENT_NAME,{}),this.newUrl=t,this.oldUrl=n}};_(re,"EVENT_NAME",de("wxt:locationchange"));let fe=re;function de(e){var t;return`${(t=ee==null?void 0:ee.runtime)==null?void 0:t.id}:content:${e}`}function In(e){let t,n;return{run(){t==null&&(n=new URL(location.href),t=e.setInterval(()=>{let i=new URL(location.href);i.href!==n.href&&(window.dispatchEvent(new fe(i,n)),n=i)},1e3))}}}const U=class U{constructor(t,n){_(this,"isTopFrame",window.self===window.top);_(this,"abortController");_(this,"locationWatcher",In(this));_(this,"receivedMessageIds",new Set);this.contentScriptName=t,this.options=n,this.abortController=new AbortController,this.isTopFrame?(this.listenForNewerScripts({ignoreFirstEvent:!0}),this.stopOldScripts()):this.listenForNewerScripts()}get signal(){return this.abortController.signal}abort(t){return this.abortController.abort(t)}get isInvalid(){return ee.runtime.id==null&&this.notifyInvalidated(),this.signal.aborted}get isValid(){return!this.isInvalid}onInvalidated(t){return this.signal.addEventListener("abort",t),()=>this.signal.removeEventListener("abort",t)}block(){return new Promise(()=>{})}setInterval(t,n){const i=setInterval(()=>{this.isValid&&t()},n);return this.onInvalidated(()=>clearInterval(i)),i}setTimeout(t,n){const i=setTimeout(()=>{this.isValid&&t()},n);return this.onInvalidated(()=>clearTimeout(i)),i}requestAnimationFrame(t){const n=requestAnimationFrame((...i)=>{this.isValid&&t(...i)});return this.onInvalidated(()=>cancelAnimationFrame(n)),n}requestIdleCallback(t,n){const i=requestIdleCallback((...r)=>{this.signal.aborted||t(...r)},n);return this.onInvalidated(()=>cancelIdleCallback(i)),i}addEventListener(t,n,i,r){var o;n==="wxt:locationchange"&&this.isValid&&this.locationWatcher.run(),(o=t.addEventListener)==null||o.call(t,n.startsWith("wxt:")?de(n):n,i,{...r,signal:this.signal})}notifyInvalidated(){this.abort("Content script context invalidated"),Nn.debug(`Content script "${this.contentScriptName}" context invalidated`)}stopOldScripts(){window.postMessage({type:U.SCRIPT_STARTED_MESSAGE_TYPE,contentScriptName:this.contentScriptName,messageId:Math.random().toString(36).slice(2)},"*")}verifyScriptStartedEvent(t){var o,s,u;const n=((o=t.data)==null?void 0:o.type)===U.SCRIPT_STARTED_MESSAGE_TYPE,i=((s=t.data)==null?void 0:s.contentScriptName)===this.contentScriptName,r=!this.receivedMessageIds.has((u=t.data)==null?void 0:u.messageId);return n&&i&&r}listenForNewerScripts(t){let n=!0;const i=r=>{if(this.verifyScriptStartedEvent(r)){this.receivedMessageIds.add(r.data.messageId);const o=n;if(n=!1,o&&(t!=null&&t.ignoreFirstEvent))return;this.notifyInvalidated()}};addEventListener("message",i),this.onInvalidated(()=>removeEventListener("message",i))}};_(U,"SCRIPT_STARTED_MESSAGE_TYPE",de("wxt:content-script-started"));let he=U;const Ln=Symbol("null");let Mn=0;class Cn extends Map{constructor(...t){super(),this._objectHashes=new WeakMap,this._symbolHashes=new Map,this._publicKeys=new Map;const[n]=t;if(n!=null){if(typeof n[Symbol.iterator]!="function")throw new TypeError(typeof n+" is not iterable (cannot read property Symbol(Symbol.iterator))");for(const[i,r]of n)this.set(i,r)}}_getPublicKeys(t,n=!1){if(!Array.isArray(t))throw new TypeError("The keys parameter must be an array");const i=this._getPrivateKey(t,n);let r;return i&&this._publicKeys.has(i)?r=this._publicKeys.get(i):n&&(r=[...t],this._publicKeys.set(i,r)),{privateKey:i,publicKey:r}}_getPrivateKey(t,n=!1){const i=[];for(const r of t){const o=r===null?Ln:r;let s;if(typeof o=="object"||typeof o=="function"?s="_objectHashes":typeof o=="symbol"?s="_symbolHashes":s=!1,!s)i.push(o);else if(this[s].has(o))i.push(this[s].get(o));else if(n){const u=`@@mkm-ref-${Mn++}@@`;this[s].set(o,u),i.push(u)}else return!1}return JSON.stringify(i)}set(t,n){const{publicKey:i}=this._getPublicKeys(t,!0);return super.set(i,n)}get(t){const{publicKey:n}=this._getPublicKeys(t);return super.get(n)}has(t){const{publicKey:n}=this._getPublicKeys(t);return super.has(n)}delete(t){const{publicKey:n,privateKey:i}=this._getPublicKeys(t);return!!(n&&super.delete(n)&&this._publicKeys.delete(i))}clear(){super.clear(),this._symbolHashes.clear(),this._publicKeys.clear()}get[Symbol.toStringTag](){return"ManyKeysMap"}get size(){return super.size}}new Cn;function _n(){}function ne(e,...t){}const Pn={debug:(...e)=>ne(console.debug,...e),log:(...e)=>ne(console.log,...e),warn:(...e)=>ne(console.warn,...e),error:(...e)=>ne(console.error,...e)};return(async()=>{try{const{main:e,...t}=An,n=new he("content",t);return await e(n)}catch(e){throw Pn.error('The content script "content" crashed on startup!',e),e}})()})();
|
|
7
|
+
content;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"manifest_version":3,"name":"WebPlater","description":"Generic browser automation bridge — Playwright alternative layer","version":"0.0.1.2607032021","key":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlljeBdeINKB8ouCR6euqG5iegaoSZY3c/uubW1AJoJzoVNyiB8UPzpL98zfWXW5nMF+KTdGa1Vb19sBACMVxO8gXEbxS/gobfqJHddfe0qZpNDEBrM7lwVJtocPb9lYJK3rHASx2VSkRFRPoymaaNDaeEO/uiu9uCG2dut/V00UvUAaeMDM9bwiWxD8aJ5IINRFIk+UniZsPB0kY3tbcmqayGYsjYpwZmU9RXoLSBZjWa8CfFjTNeyPBtLpkj2groQN/Ytk1RWf5AEwAPIahfz/hn2kDOnL1OSNGyQfswL8GuWJZs9h2bvDQMKwCRUQ/iUuqypNQfbin42rpD1kz9QIDAQAB","permissions":["tabs","scripting","cookies","storage","offscreen","webNavigation","downloads"],"host_permissions":["<all_urls>"],"background":{"service_worker":"background.js"},"action":{"default_title":"WebPlater","default_popup":"popup.html"},"content_scripts":[{"matches":["<all_urls>"],"all_frames":true,"run_at":"document_idle","js":["content-scripts/content.js"]}]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>WebPlater Offscreen</title>
|
|
6
|
+
<script type="module" crossorigin src="/chunks/offscreen-CFXYw9Mo.js"></script>
|
|
7
|
+
<link rel="modulepreload" crossorigin href="/chunks/_virtual_wxt-html-plugins-DPbbfBKe.js">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<!--
|
|
11
|
+
offscreen document:常驻宿主,持有到 browserd 的 WebSocket 长连接。
|
|
12
|
+
页面本身无 UI,仅承载 main.ts 的 WS 桥接逻辑。
|
|
13
|
+
由 background.ts 的 ensureOffscreen() 创建。
|
|
14
|
+
-->
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>WebPlater</title>
|
|
7
|
+
<script type="module" crossorigin src="/chunks/popup-C-lpxZZO.js"></script>
|
|
8
|
+
<link rel="modulepreload" crossorigin href="/chunks/_virtual_wxt-html-plugins-DPbbfBKe.js">
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/popup-BUZEUmsx.css">
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="app">
|
|
13
|
+
<header>
|
|
14
|
+
<h1>WebPlater</h1>
|
|
15
|
+
<p id="status" class="status">checking...</p>
|
|
16
|
+
</header>
|
|
17
|
+
|
|
18
|
+
<section>
|
|
19
|
+
<h2>调试</h2>
|
|
20
|
+
<div class="row">
|
|
21
|
+
<button id="btn-tabs">List Tabs</button>
|
|
22
|
+
<button id="btn-status">Page Status</button>
|
|
23
|
+
<button id="btn-reconnect">Reconnect</button>
|
|
24
|
+
</div>
|
|
25
|
+
</section>
|
|
26
|
+
|
|
27
|
+
<pre id="result">Ready</pre>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|