dsh-free-search 0.9.8 → 0.9.9
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 +4 -2
- package/lib/client.js +1 -1
- package/lib/fetch_provider.js +28 -1
- package/lib/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -472,7 +472,7 @@ Search engine test:
|
|
|
472
472
|
|
|
473
473
|
#### 离线自检断言(tools/)
|
|
474
474
|
|
|
475
|
-
仓库自带 **
|
|
475
|
+
仓库自带 **20 个**零依赖断言脚本(合计 **534 项**),**不需要 API key、不联网、不需要测试框架**,Node ≥ 20 即可跑:
|
|
476
476
|
|
|
477
477
|
| 脚本 | 覆盖 | 运行(项数) |
|
|
478
478
|
|---|---|---|
|
|
@@ -492,6 +492,7 @@ Search engine test:
|
|
|
492
492
|
| `assert-killtree-win32.mjs` | Windows 子进程树终止(#74):不再依赖 `taskkill` | `node tools/assert-killtree-win32.mjs`(8) |
|
|
493
493
|
| `assert-killtree-portable.mjs` | 跨平台 `killTree` 便携版契约 | `node tools/assert-killtree-portable.mjs`(5) |
|
|
494
494
|
| `assert-parallel-mcp.mjs` | Parallel MCP 引擎:25 s 超时/调用方取消覆盖**响应体读取**、共享 SSE 解析器(通知/多行帧)、6 类错误路径、REST 精确时间过滤 | `node tools/assert-parallel-mcp.mjs`(15) |
|
|
495
|
+
| `assert-fetch-charset.mjs` | 抓取编码(#88):`charset=gbk` / `gb2312` 按声明解码、无声明时嗅探 `<meta charset>` 与 http-equiv 形式、默认 UTF-8、未知 label 兜底 UTF-8 不抛错 | `node tools/assert-fetch-charset.mjs`(6) |
|
|
495
496
|
| `assert-fetch-abort.mjs` | 抓取中断(#87):压缩响应中途断连必须 reject(不再永久 pending)、明文断连同样 reject、abort 能打断停滞的 gzip 流、complete 响应与重定向仍正常 | `node tools/assert-fetch-abort.mjs`(6) |
|
|
496
497
|
| `assert-bridge-access.mjs` | 桥接 Host 围栏(#84):loopback 放行、remote peer 打 loopback Host 拒绝、`--trusted-host`(无端口匹配任意端口 / 带端口精确匹配)、`--public-url`、绑定地址、跨站与异源拒绝 | `node tools/assert-bridge-access.mjs`(11) |
|
|
497
498
|
| `assert-provider-takeover.mjs` | provider 接管:旧属性 API 与 rc.2 的 `config.*` ref 两套兼容、`settings.mutate(web)` 单批写入、显式指定的 provider 不被抢占、`fetchProviderTakeover: false` 时保留显式 `http`、describe 噪声不误报、嵌套 config 变化与 web 重建分别成行、关闭 DSH 搜索开关后重新接管且不抢 `deepseek-search-api`、apply 重入/重复注册不再中断、重复日志去重 | `node tools/assert-provider-takeover.mjs`(16) |
|
|
@@ -987,7 +988,7 @@ Restart `dsh web` after switching to apply changes.
|
|
|
987
988
|
|
|
988
989
|
#### Offline self-check assertions (`tools/`)
|
|
989
990
|
|
|
990
|
-
**
|
|
991
|
+
**Twenty** zero-dependency assertion scripts ship with the repo (**534 assertions** total): **no API keys, no network, no test framework**, Node ≥ 20:
|
|
991
992
|
|
|
992
993
|
| Script | Covers | Run (count) |
|
|
993
994
|
|---|---|---|
|
|
@@ -1007,6 +1008,7 @@ Restart `dsh web` after switching to apply changes.
|
|
|
1007
1008
|
| `assert-killtree-win32.mjs` | Windows process-tree termination (#74): no longer relies on `taskkill` | `node tools/assert-killtree-win32.mjs` (8) |
|
|
1008
1009
|
| `assert-killtree-portable.mjs` | portable `killTree` contract | `node tools/assert-killtree-portable.mjs` (5) |
|
|
1009
1010
|
| `assert-parallel-mcp.mjs` | Parallel MCP engine: the 25 s timeout / caller abort covers the **body read**, shared SSE parser (notifications, multiline frames), six error paths, REST precise time filtering | `node tools/assert-parallel-mcp.mjs` (15) |
|
|
1011
|
+
| `assert-fetch-charset.mjs` | fetch encoding (#88): `charset=gbk` / `gb2312` decoded as declared, `<meta charset>` and the http-equiv form sniffed when the header omits it, UTF-8 by default, and an unknown label falls back to UTF-8 instead of throwing | `node tools/assert-fetch-charset.mjs` (6) |
|
|
1010
1012
|
| `assert-fetch-abort.mjs` | fetch interruption (#87): a compressed response cut mid-body rejects instead of hanging forever, identity truncation rejects too, abort breaks a stalled gzip stream, and complete responses plus redirects still work | `node tools/assert-fetch-abort.mjs` (6) |
|
|
1011
1013
|
| `assert-bridge-access.mjs` | bridge Host fence (#84): loopback allowed, a remote peer behind a loopback Host refused, `--trusted-host` (port-less matches any port, explicit port matches exactly), `--public-url`, the bind address, cross-site and foreign-Origin refused | `node tools/assert-bridge-access.mjs` (11) |
|
|
1012
1014
|
| `assert-provider-takeover.mjs` | provider takeover: both the legacy property API and the rc.2 `config.*` refs, a single batched `settings.mutate(web)`, explicit foreign providers left untouched, an explicit `http` kept when `fetchProviderTakeover` is off, describe()-triggered events ignored when nothing changed, nested config changes and web rebuilds reported separately, re-takeover after DSH's search switch is turned off without fighting an explicit `deepseek-search-api`, apply re-entry / duplicate registrations tolerated, and repeated logs deduplicated | `node tools/assert-provider-takeover.mjs` (16) |
|
package/lib/client.js
CHANGED
|
@@ -426,7 +426,7 @@ window.__ModuleLoader__.load({
|
|
|
426
426
|
};
|
|
427
427
|
const tt = (lang) => I18N[lang === "en" ? "en" : "zh"];
|
|
428
428
|
// 当前插件版本(与 lib/index.js 的 PLUGIN_VERSION 保持一致;跟随上游 v0.7.5)
|
|
429
|
-
const PLUGIN_VERSION = "0.9.
|
|
429
|
+
const PLUGIN_VERSION = "0.9.9";
|
|
430
430
|
const PLUGIN_REPO_URL = "https://github.com/DDDMUC/dsh-free-search";
|
|
431
431
|
// 右侧浮动目录(#85):条目顺序即页面顺序,anchor 是页面里对应 field 的 id。
|
|
432
432
|
const NAV_ITEMS = [
|
package/lib/fetch_provider.js
CHANGED
|
@@ -122,6 +122,33 @@ function browserDumpDom(browserPath, url, { timeoutMs = 25000, signal } = {}) {
|
|
|
122
122
|
});
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
// #88:按声明的 charset 解码。GBK/GB2312/Big5/Shift_JIS 老站很常见,
|
|
126
|
+
// 一律当 UTF-8 会得到整页 \uFFFD,而且不会报错、不会降级,模型直接吃一页乱码。
|
|
127
|
+
function parseCharset(contentType) {
|
|
128
|
+
const match = /charset\s*=\s*"?([^";\s]+)"?/i.exec(String(contentType || ""));
|
|
129
|
+
return match ? match[1].trim().toLowerCase() : "";
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function sniffHtmlCharset(buffer) {
|
|
133
|
+
const head = buffer.subarray(0, 2048).toString("latin1");
|
|
134
|
+
let match = /<meta[^>]+charset\s*=\s*["']?\s*([\w.:-]+)/i.exec(head);
|
|
135
|
+
if (match) return match[1].toLowerCase();
|
|
136
|
+
match = /<meta[^>]+content\s*=\s*["'][^"']*charset\s*=\s*([\w.:-]+)/i.exec(head);
|
|
137
|
+
return match ? match[1].toLowerCase() : "";
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function decodeBody(buffer, contentType) {
|
|
141
|
+
let label = parseCharset(contentType);
|
|
142
|
+
if (!label && /html|xml/i.test(String(contentType || ""))) label = sniffHtmlCharset(buffer);
|
|
143
|
+
if (!label) label = "utf-8";
|
|
144
|
+
try {
|
|
145
|
+
return new TextDecoder(label, { fatal: false }).decode(buffer);
|
|
146
|
+
} catch {
|
|
147
|
+
// 无法识别的 label(或该 Node 没编进对应编码表):退回 UTF-8,不抛错。
|
|
148
|
+
return buffer.toString("utf8");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
125
152
|
/** GET 跟随重定向(≤5 跳),返回最终 URL / 状态 / 正文 / 内容类型;支持 gzip/br/deflate 解压。 */
|
|
126
153
|
export function httpsGetFollow(url, { headers = {}, timeoutMs = 20000, signal } = {}, transport = https) {
|
|
127
154
|
return new Promise((resolve, reject) => {
|
|
@@ -222,7 +249,7 @@ export function httpsGetFollow(url, { headers = {}, timeoutMs = 20000, signal }
|
|
|
222
249
|
settle(true, {
|
|
223
250
|
url: current,
|
|
224
251
|
status: res.statusCode,
|
|
225
|
-
text: Buffer.concat(chunks).
|
|
252
|
+
text: decodeBody(Buffer.concat(chunks), res.headers["content-type"] || ""),
|
|
226
253
|
contentType: res.headers["content-type"] || "",
|
|
227
254
|
})
|
|
228
255
|
);
|
package/lib/index.js
CHANGED
|
@@ -256,7 +256,7 @@ function routeEngines(query, { timeRange, disabledEngines = [], fallbackOrder =
|
|
|
256
256
|
}
|
|
257
257
|
|
|
258
258
|
// 当前插件版本(发布时与 package.json 同步;跟随上游 v0.7.5,不在 PR 里 bump)
|
|
259
|
-
const PLUGIN_VERSION = "0.9.
|
|
259
|
+
const PLUGIN_VERSION = "0.9.9";
|
|
260
260
|
// 检查更新的 npm registry 元数据地址(dsh-free-search 是 npmjs 上的公开包)
|
|
261
261
|
const NPM_REGISTRY_URL = "https://registry.npmjs.org/dsh-free-search/latest";
|
|
262
262
|
const PLUGIN_NPM_URL = "https://www.npmjs.com/package/dsh-free-search";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-free-search",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.9",
|
|
4
4
|
"description": "Free web search for DeepSeek Harness: 27 engines (Bing/DuckDuckGo/AnySearch/SearXNG/Exa/Tavily/Keenable/Firecrawl/Parallel keyless; Zhihu global/site via MCP and Perplexity/SerpBase/DeepSeek (official + native tools/search)/You.com/Baidu/Kimi/Aliyun/Doubao with key; OpenAI/Gemini/Claude model built-in search, explicit-only) + auto smart routing + global engine enable/disable & fallback priority + editable zh/en language pools + multi mode (parallel full language-pool merge) + multi_search cross-source tool + failure-aware fallback (quota/auth cooldown, transient retry, fallbackOn) + time filtering + platform search + domain blocklist (blockedDomains) + web_fetch, with web settings UI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|