dsh-site-bridge 0.8.0 → 0.8.1
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/docs/limitations.md +2 -1
- package/extension/manifest.json +1 -1
- package/extension/sw.js +27 -6
- package/package.json +1 -1
package/docs/limitations.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Ограничения: что именно ломается и как это снять
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Пять ограничений, которые чаще всего мешают на реальных сайтах. Для каждого: наблюдаемое
|
|
4
4
|
поведение, причина (со ссылкой на код), что нужно изменить и сколько это стоит.
|
|
5
5
|
|
|
6
6
|
| # | Ограничение | Статус | Что осталось |
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
| 2 | shadow DOM частично | **частично снято** | открытые корни: селекторы-цепочки и поиск работают; закрытые корни не видны |
|
|
10
10
|
| 3 | тело ответа ≤ 400 КБ | **снято** | лимит 5 МБ в воркере, тела > 200 КБ выносятся в `bodies/<id>.json` |
|
|
11
11
|
| 4 | один таб на сессию | **снято** | `Map<tabId, session>`, `tabId` в командах, переключатель в попапе |
|
|
12
|
+
| 5 | Chrome отказывает в `chrome.debugger.attach` отдельной вкладке (`Cannot access a chrome-extension:// URL of different extension`) | открыто | воспроизведено на `mail.google.com`: соседние сайты подключаются, Gmail — нет, при этом `tabs.get` вкладку отдаёт, а в списке целей у неё обычный `page` с https-адресом. Обход не найден; `site_tabs {action:"diagnose"}` показывает, что видит Chrome |
|
|
12
13
|
|
|
13
14
|
Ниже — исходный разбор каждого ограничения; для снятых пунктов оставлено описание того, что
|
|
14
15
|
именно было изменено и какие границы остались.
|
package/extension/manifest.json
CHANGED
package/extension/sw.js
CHANGED
|
@@ -88,18 +88,27 @@ async function evt(kind, payload = {}) {
|
|
|
88
88
|
|
|
89
89
|
let looping = false
|
|
90
90
|
|
|
91
|
+
/** Runs a promise with a deadline, so one stuck Chrome call cannot park the loop. */
|
|
92
|
+
function withDeadline(promise, ms, label) {
|
|
93
|
+
return Promise.race([
|
|
94
|
+
promise,
|
|
95
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`${label} не ответил за ${ms} мс`)), ms))
|
|
96
|
+
])
|
|
97
|
+
}
|
|
98
|
+
|
|
91
99
|
async function ensureLoop() {
|
|
92
100
|
if (looping) return
|
|
93
101
|
looping = true
|
|
94
102
|
let greeted = false
|
|
95
103
|
try {
|
|
96
104
|
for (;;) {
|
|
97
|
-
|
|
98
|
-
if (!cfg.token) {
|
|
99
|
-
await sleep(1500)
|
|
100
|
-
continue
|
|
101
|
-
}
|
|
105
|
+
state.lastTick = Date.now()
|
|
102
106
|
try {
|
|
107
|
+
const cfg = await loadCfg()
|
|
108
|
+
if (!cfg.token) {
|
|
109
|
+
await sleep(1500)
|
|
110
|
+
continue
|
|
111
|
+
}
|
|
103
112
|
const reply = await api(cfg, '/v1/poll?timeout=20000')
|
|
104
113
|
if (!greeted) {
|
|
105
114
|
greeted = true
|
|
@@ -115,7 +124,7 @@ async function ensureLoop() {
|
|
|
115
124
|
state.attempts = 0
|
|
116
125
|
for (const command of reply.commands || []) {
|
|
117
126
|
// Sequential: a command may pin a tab for its whole duration.
|
|
118
|
-
await runCommand(cfg, command)
|
|
127
|
+
await withDeadline(runCommand(cfg, command), 120000, `команда ${command?.op ?? '?'}`)
|
|
119
128
|
}
|
|
120
129
|
} catch (error) {
|
|
121
130
|
greeted = false
|
|
@@ -129,6 +138,16 @@ async function ensureLoop() {
|
|
|
129
138
|
}
|
|
130
139
|
}
|
|
131
140
|
|
|
141
|
+
// If the loop parks on a Chrome call that never settles, restart it.
|
|
142
|
+
setInterval(() => {
|
|
143
|
+
if (!looping) return
|
|
144
|
+
if (Date.now() - (state.lastTick ?? 0) > 90000) {
|
|
145
|
+
state.lastError = 'цикл опроса завис, перезапускаю'
|
|
146
|
+
looping = false
|
|
147
|
+
void ensureLoop()
|
|
148
|
+
}
|
|
149
|
+
}, 30000)
|
|
150
|
+
|
|
132
151
|
function sleep(ms) {
|
|
133
152
|
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
134
153
|
}
|
|
@@ -186,6 +205,8 @@ async function handleMessageInner(message) {
|
|
|
186
205
|
connected: state.lastPollOk > 0 && Date.now() - state.lastPollOk < 45000,
|
|
187
206
|
lastError: state.lastError ?? null,
|
|
188
207
|
attempts: state.attempts || 0,
|
|
208
|
+
loopAlive: looping,
|
|
209
|
+
lastTickAgoMs: state.lastTick ? Date.now() - state.lastTick : null,
|
|
189
210
|
target: active?.target ?? null,
|
|
190
211
|
activeTabId: state.activeTabId,
|
|
191
212
|
targets: [...state.sessions.values()].map((session) => ({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-site-bridge",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Chrome/Edge MV3 bridge for DeepSeek Harness: capture page markup (DOM, styles, selectors) and BFF traffic (xhr/fetch with headers and bodies) into a workspace snapshot bundle, drive the page with trusted CDP input, and verify injected scripts. Authorization never leaves the browser and is never written to disk.",
|
|
5
5
|
"icon": "./icon.svg",
|
|
6
6
|
"type": "module",
|