@240xu/dsh-websearch 2.0.1 → 2.0.3
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/lib/client.js +45 -27
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -26,7 +26,19 @@ window.__ModuleLoader__.load({
|
|
|
26
26
|
];
|
|
27
27
|
const GLOBAL_FIELDS = ["numResults", "concurrency", "backendTimeoutMs"];
|
|
28
28
|
|
|
29
|
+
/** Where the user goes to get/rotate each key. */
|
|
30
|
+
const KEY_URLS = {
|
|
31
|
+
brave: "https://api-dashboard.search.brave.com/app/keys",
|
|
32
|
+
tavily: "https://app.tavily.com/home",
|
|
33
|
+
serper: "https://serper.dev/api-key",
|
|
34
|
+
mojeek: "https://www.mojeek.com/services/search/web-search-api/",
|
|
35
|
+
deepseek: "https://platform.deepseek.com/api_keys",
|
|
36
|
+
anthropic: "https://console.anthropic.com/settings/keys",
|
|
37
|
+
openai: "https://platform.openai.com/api-keys",
|
|
38
|
+
};
|
|
39
|
+
|
|
29
40
|
const zh = {
|
|
41
|
+
nav: "搜索",
|
|
30
42
|
title: "统一搜索 (Unified Search)",
|
|
31
43
|
description: "聚合网络搜索:11 个后端并发 fan-out、URL 去重合并。开关后端、填 API Key、调参数,保存即生效。",
|
|
32
44
|
save: "保存",
|
|
@@ -38,6 +50,7 @@ window.__ModuleLoader__.load({
|
|
|
38
50
|
reset: "重置",
|
|
39
51
|
overridden: "已自定义",
|
|
40
52
|
keyLabel: "{id} API Key",
|
|
53
|
+
getKey: "获取 Key ↗",
|
|
41
54
|
keyHint: "填入后保存到凭证库(对应环境变量引用);留空表示不修改",
|
|
42
55
|
keySet: "已配置",
|
|
43
56
|
keyUnset: "未配置",
|
|
@@ -45,6 +58,7 @@ window.__ModuleLoader__.load({
|
|
|
45
58
|
globalsTitle: "全局参数",
|
|
46
59
|
};
|
|
47
60
|
const en = {
|
|
61
|
+
nav: "Web Search",
|
|
48
62
|
title: "Unified Search",
|
|
49
63
|
description: "Aggregated web search: 11 backends fan out concurrently, URL-deduped. Toggle backends, set API keys, tune globals — saves apply immediately.",
|
|
50
64
|
save: "Save",
|
|
@@ -56,6 +70,7 @@ window.__ModuleLoader__.load({
|
|
|
56
70
|
reset: "Reset",
|
|
57
71
|
overridden: "customized",
|
|
58
72
|
keyLabel: "{id} API Key",
|
|
73
|
+
getKey: "Get key ↗",
|
|
59
74
|
keyHint: "Stored into the credential store on save; leave blank to keep current",
|
|
60
75
|
keySet: "configured",
|
|
61
76
|
keyUnset: "not set",
|
|
@@ -85,10 +100,6 @@ window.__ModuleLoader__.load({
|
|
|
85
100
|
};
|
|
86
101
|
}
|
|
87
102
|
|
|
88
|
-
function useStore(store, selector = (s) => s) {
|
|
89
|
-
return react.useSyncExternalStore(store.subscribe, () => selector(store.getSnapshot()));
|
|
90
|
-
}
|
|
91
|
-
|
|
92
103
|
/**
|
|
93
104
|
* Card state machine: reads the bound settings scope snapshot, stages edits,
|
|
94
105
|
* writes section fields through scope.set/unset and secrets via credentials.
|
|
@@ -199,16 +210,16 @@ window.__ModuleLoader__.load({
|
|
|
199
210
|
}
|
|
200
211
|
|
|
201
212
|
inject() {
|
|
213
|
+
// Slot contract: hooks.{name} must be an observable store; the renderer
|
|
214
|
+
// converts it into props.use{Name} (observableHook). Actions go top-level.
|
|
202
215
|
return {
|
|
203
|
-
hooks: {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
discard: () => { this.staged.clear(); this.stagedKeys.clear(); this.failed = false; this.republish(); },
|
|
211
|
-
},
|
|
216
|
+
hooks: { unifiedSearchCard: this.store },
|
|
217
|
+
edit: (f, t) => this.edit(f, t),
|
|
218
|
+
setToggle: (id, checked) => this.setToggle(id, checked),
|
|
219
|
+
reset: (f) => this.reset(f),
|
|
220
|
+
editKey: (r, t) => this.editKey(r, t),
|
|
221
|
+
save: () => this.save(),
|
|
222
|
+
discard: () => { this.staged.clear(); this.stagedKeys.clear(); this.failed = false; this.republish(); },
|
|
212
223
|
};
|
|
213
224
|
}
|
|
214
225
|
}
|
|
@@ -230,17 +241,17 @@ window.__ModuleLoader__.load({
|
|
|
230
241
|
}
|
|
231
242
|
|
|
232
243
|
/** The card root. */
|
|
233
|
-
function
|
|
234
|
-
const
|
|
235
|
-
const
|
|
244
|
+
function UnifiedSearchSection(props) {
|
|
245
|
+
const state = props.useUnifiedSearchCard((snapshot) => snapshot);
|
|
246
|
+
const card = { edit: props.edit, setToggle: props.setToggle, reset: props.reset, editKey: props.editKey, save: props.save, discard: props.discard };
|
|
236
247
|
// Occupants of settings.plugin.item render inside the tab's <ul>; use <li>.
|
|
237
248
|
if (!state.ready) {
|
|
238
|
-
return react_jsx_runtime.jsx("
|
|
249
|
+
return react_jsx_runtime.jsx("div", { className: "wsc-card", style: { fontSize: 12, opacity: .6 }, children: "…" });
|
|
239
250
|
}
|
|
240
251
|
|
|
241
252
|
const toggleField = (id) => "enable" + id.charAt(0).toUpperCase() + id.slice(1);
|
|
242
253
|
|
|
243
|
-
return react_jsx_runtime.jsxs("
|
|
254
|
+
return react_jsx_runtime.jsxs("div", { className: "wsc-card", children: [
|
|
244
255
|
react_jsx_runtime.jsx("p", { style: { margin: 0, fontSize: 12, opacity: .65 }, children: props.t("description") }),
|
|
245
256
|
react_jsx_runtime.jsx("h4", { className: "wsc-sectionTitle", children: props.t("togglesTitle") }),
|
|
246
257
|
react_jsx_runtime.jsx("div", { className: "wsc-toggles", children: BACKENDS.map((b) =>
|
|
@@ -270,7 +281,14 @@ window.__ModuleLoader__.load({
|
|
|
270
281
|
react_jsx_runtime.jsxs("div", { children: [
|
|
271
282
|
react_jsx_runtime.jsxs("div", { className: "wsc-fieldHead", children: [
|
|
272
283
|
react_jsx_runtime.jsx("span", { className: "wsc-label", children: props.t("keyLabel", { id: b.id }) }),
|
|
273
|
-
react_jsx_runtime.
|
|
284
|
+
react_jsx_runtime.jsxs("span", { className: "wsc-badges", style: { display: "flex", gap: 6, alignItems: "center" }, children: [
|
|
285
|
+
KEY_URLS[b.id] && react_jsx_runtime.jsx("a", {
|
|
286
|
+
href: KEY_URLS[b.id], target: "_blank", rel: "noreferrer",
|
|
287
|
+
style: { fontSize: 11, color: "var(--dsw-alias-accent-primary)", textDecoration: "none" },
|
|
288
|
+
children: props.t("getKey"),
|
|
289
|
+
}),
|
|
290
|
+
react_jsx_runtime.jsx("span", { className: "wsc-badge" + (state.keyState[b.keyEnv]?.configured ? " wsc-badgeOn" : ""), children: state.keyState[b.keyEnv]?.configured ? props.t("keySet") : props.t("keyUnset") }),
|
|
291
|
+
] }),
|
|
274
292
|
] }),
|
|
275
293
|
react_jsx_runtime.jsx("input", {
|
|
276
294
|
className: "wsc-keyInput", type: "password", autoComplete: "off",
|
|
@@ -299,14 +317,14 @@ window.__ModuleLoader__.load({
|
|
|
299
317
|
ctx.get("remote"),
|
|
300
318
|
);
|
|
301
319
|
ctx.effect(() => ctx.remote.$on("credentials/updated", () => controller.refreshAllCredentials()), "websearch: credential invalidations");
|
|
302
|
-
ctx.slots.inject("settings.
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
});
|
|
320
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
321
|
+
name: "settings.section",
|
|
322
|
+
id: "websearch",
|
|
323
|
+
order: 16,
|
|
324
|
+
label: () => t("nav"),
|
|
325
|
+
locale: NS,
|
|
326
|
+
inject: () => controller.inject(),
|
|
327
|
+
}, UnifiedSearchSection));
|
|
310
328
|
controller.refreshAllCredentials();
|
|
311
329
|
}
|
|
312
330
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@240xu/dsh-websearch",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Unified web search provider for DeepSeek Harness (ctx.web): 11 backends — Exa + Parallel + DDG + SearXNG (keyless), DeepSeek + Anthropic + OpenAI + Brave + Tavily + Serper + Mojeek (key-gated via Settings credentials). Registers provider id \"unified\" for zero-config web_search tool.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|