// ==UserScript==
// @name DQ Client (for DeepQuery Secure)
// @namespace dq.secure.client
// @version 1.0.0
// @description 客户端:把查询请求放到 GM 通道,等待结果返回
// @match http://*/*
// @match https://*/*
// @include about:blank
// @run-at document-start
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addValueChangeListener
// @grant GM_removeValueChangeListener
// @grant GM_getTab
// @grant GM_saveTab
// ==/UserScript==
(function(){
'use strict';
const now = () => Date.now();
const rid = () => (now().toString(36) + Math.random().toString(36).slice(2,8)).toUpperCase();
function getTabId(){
return new Promise(resolve=>{
GM_getTab(tab=>{
if(!tab) tab = {};
if(!tab.__dq_tab_id__){ tab.__dq_tab_id__ = rid(); try{ GM_saveTab(tab); }catch{} }
resolve(tab.__dq_tab_id__);
});
});
}
async function request(spec){
const TAB_ID = await getTabId();
const reqId = rid();
const KEY_REQ = `DQ_REQ:${TAB_ID}`;
const KEY_RES = `DQ_RES:${TAB_ID}:${reqId}`;
return await new Promise((resolve)=>{
const lid = GM_addValueChangeListener(KEY_RES, (name, oldVal, val, remote)=>{
if(!remote) return;
try{ GM_removeValueChangeListener(lid); }catch{}
try{ GM_setValue(name, null); }catch{}
resolve(val);
});
GM_setValue(KEY_REQ, { tabId: TAB_ID, reqId, spec, at: Date.now() });
});
}
// 语法糖,保持与旧 API 一致
const DQ = {
get: (spec)=>request(spec),
attr: ({framePath, chain, name, timeout, frameTimeout}) => request({framePath, chain, timeout, frameTimeout, pick: {attr: name}}),
prop: ({framePath, chain, name, timeout, frameTimeout}) => request({framePath, chain, timeout, frameTimeout, pick: {prop: name}}),
text: ({framePath, chain, timeout, frameTimeout}) => request({framePath, chain, timeout, frameTimeout, pick: {text: true}}),
html: ({framePath, chain, timeout, frameTimeout}) => request({framePath, chain, timeout, frameTimeout, pick: {html: true}}),
rect: ({framePath, chain, timeout, frameTimeout}) => request({framePath, chain, timeout, frameTimeout, pick: {rect: true}})
};
// 暴露到当前脚本的沙箱(不是 page)
window.DQ = DQ;
try{ console.debug('[DQ Client] ready: use await DQ.get({...})'); }catch{}
})();