@klarkxy/dsh-web-search-manager 0.1.9 → 0.1.10
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 +32 -19
- package/docs/README.zh-CN.md +31 -18
- package/lib/client.inner.cjs +942 -299
- package/lib/client.inner.cjs.map +1 -1
- package/lib/client.js +942 -299
- package/lib/index.js +51 -21
- package/lib/index.js.map +1 -1
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +13 -6
package/lib/client.inner.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.inner.cjs","names":["useState","useRef","useId"],"sources":["../src/provider-info.ts","../src/contracts.ts","../src/client.tsx"],"sourcesContent":["import type { ProviderView } from './contracts.ts'\n\n// Public prices checked on 2026-09-21; links remain available for current account terms.\nexport const PROVIDER_PRICING_CHECKED = '2026-09-21'\n\ninterface ProviderInfo {\n description: string\n pricing: string\n pricingUrl?: string\n}\n\nconst providerInfo: Record<string, ProviderInfo> = {\n ddg: {\n description: '搜索 DuckDuckGo 公开网页,无需注册或 API Key。',\n pricing: '免费使用,不产生搜索 API 费用。',\n pricingUrl: 'https://duckduckgo.com/',\n },\n bocha: {\n description: '面向中文内容的网页搜索,返回标题、链接和摘要。',\n pricing: '按调用次数计费,目录价 ¥0.036/次;试用额度以官方活动为准。',\n pricingUrl: 'https://aq6ky2b8nql.feishu.cn/wiki/JYSbwzdPIiFnz4kDYPXcHSDrnZb',\n },\n brave: {\n description: '使用 Brave 独立网页索引,搜索网页、新闻等内容。',\n pricing: '每月赠 $5(约 1,000 次);超出 $5/千次,激活需绑卡。',\n pricingUrl: 'https://brave.com/search/api/',\n },\n 'deepseek-official': {\n description: '由 DeepSeek 模型调用内置搜索,复用模型 API Key。',\n pricing: '默认 Flash 按 tokens 计费:每百万输入 ¥1–2(缓存命中 ¥0.02–0.04)、输出 ¥4–8,随峰谷时段变化;赠送余额和搜索工具费用以平台为准。',\n pricingUrl: 'https://api-docs.deepseek.com/zh-cn/quick_start/pricing/',\n },\n exa: {\n description: '面向 AI 的网页搜索,提供相关网页与内容片段。',\n pricing: '注册赠 $20,此后每月赠 $10;$7/千次(每次最多 10 条),超过 10 条每多一条加 $1/千次。',\n pricingUrl: 'https://exa.ai/pricing',\n },\n firecrawl: {\n description: '搜索网页,并可配合网页内容提取。',\n pricing: '每月免费 1,000 积分,搜索每 10 条结果扣 2 积分;Hobby 含 5,000 积分/月,年付折合 $16/月,额外 $5/千积分。',\n pricingUrl: 'https://www.firecrawl.dev/pricing',\n },\n serper: {\n description: '获取 Google 的网页搜索结果。',\n pricing: '注册赠 2,500 次(一次性);充值 $50/5万次($1/千次),付费额度有效期 6 个月。',\n pricingUrl: 'https://serper.dev/',\n },\n tavily: {\n description: '面向 AI 的网页搜索,当前使用基础搜索。',\n pricing: '每月免费 1,000 积分,基础搜索 1 积分/次;按量付费 $0.008/积分($8/千次)。',\n pricingUrl: 'https://docs.tavily.com/documentation/api-credits',\n },\n}\n\nexport function searchProviderInfo(provider: ProviderView): ProviderInfo {\n const known = Object.hasOwn(providerInfo, provider.id) ? providerInfo[provider.id] : undefined\n return {\n description: known?.description ?? provider.description,\n pricing: provider.pricing ?? known?.pricing ?? (provider.billing === 'none' ? '此后端不收取搜索费用。'\n : provider.billing === 'model-and-tools' ? '按模型用量和工具调用计费;免费额度及单价请查看供应商说明。'\n : '按 API 调用计费;免费额度及单价请查看供应商说明。'),\n pricingUrl: provider.pricingUrl ?? known?.pricingUrl ?? provider.signupUrl,\n }\n}\n","import type { WebFetchProvider, WebSearchProvider } from '@deepseek-ai/dsh-web'\n\nexport const WEB_SEARCH_RPC_CHANNEL = '/web-search-manager'\nexport type RpcResult<T = unknown> = { ok: true; value: T } | {\n ok: false; error: { code: string; message: string; details: Record<string, unknown> }\n}\nexport type ProviderKind = 'search' | 'fetch'\n/** Management metadata only. Execution and source vocabulary belong to ctx.web. */\nexport interface ProviderDescriptor {\n readonly id: string\n readonly label: string\n readonly description: string\n readonly defaultBaseURL?: string\n readonly credentialRef?: string\n /** True when the key is shared with another surface. The page must not delete it. */\n readonly credentialShared?: boolean\n /** Optional notice naming the settings surface that owns a shared credential. */\n readonly credentialHint?: string\n readonly billing: 'request' | 'model-and-tools' | 'none'\n /** Optional provider-supplied billing summary. */\n readonly pricing?: string\n /** Public HTTPS page explaining provider charges. */\n readonly pricingUrl?: string\n /** Public HTTPS page where the user can create an API key. */\n readonly signupUrl?: string\n}\nexport interface ProviderOptions {\n readonly apiKey?: string\n readonly baseURL?: string\n readonly timeoutMs: number\n readonly maxFetchChars: number\n}\nexport type SearchProviderFactory = (options: ProviderOptions) => WebSearchProvider\nexport type FetchProviderFactory = (options: ProviderOptions) => WebFetchProvider\n/** Never store credential values here. Keys are resolved by reference per call. */\nexport interface WebSettings {\n revision: number\n searchEnabled: boolean\n fetchEnabled: boolean\n searchProvider: string\n fetchProvider: string\n searchOrder: string[]\n maxResults: number\n maxQueries: number\n timeoutMs: number\n maxFetchChars: number\n endpoints: Record<string, string>\n}\nexport const DEFAULT_SEARCH_ORDER = ['ddg'] as const\n\nexport const defaultSettings = (): WebSettings => ({\n revision: 0, searchEnabled: true, fetchEnabled: true,\n searchProvider: 'ddg', fetchProvider: 'http', searchOrder: [...DEFAULT_SEARCH_ORDER],\n maxResults: 5, maxQueries: 1,\n timeoutMs: 30_000, maxFetchChars: 100_000, endpoints: {},\n})\n\n/** Keyed backends first, keyless last — same idea as OpenClaw auto-detect. */\nexport function defaultSearchOrder(ids: readonly string[], keyed: (id: string) => boolean): string[] {\n return [...ids.filter(keyed), ...ids.filter(id => !keyed(id))]\n}\n\nexport function migrateSearchOrder(settings: { searchOrder?: string[]; searchProvider?: string }): string[] {\n return settings.searchOrder ?? (settings.searchProvider ? [settings.searchProvider] : [...DEFAULT_SEARCH_ORDER])\n}\n\nexport function resolveSearchOrder(\n knownIds: readonly string[],\n settings: Pick<WebSettings, 'searchOrder' | 'searchProvider'>,\n _keyed: (id: string) => boolean,\n): string[] {\n return [...new Set(settings.searchOrder.filter(id => knownIds.includes(id)))]\n}\n\nexport function pickActiveSearch(order: readonly string[], configured: (id: string) => boolean): string {\n return order.find(configured) ?? ''\n}\nexport interface ProviderView extends ProviderDescriptor {\n kind: ProviderKind\n configured: boolean\n baseURL?: string\n calls: number\n failures: number\n}\nexport interface WebStatus {\n settings: WebSettings\n providers: ProviderView[]\n searchActive: boolean\n fetchActive: boolean\n storageFailed: boolean\n}\nexport function providerKey(kind: ProviderKind, id: string): string { return `${kind}:${id}` }\nexport function validateBaseURL(value: string): string {\n const url = new URL(value)\n if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash) {\n throw new Error('供应商地址必须是 HTTPS,且不能包含用户名、密码、查询参数或片段。')\n }\n return url.href.replace(/\\/+$/, '')\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { useEffect, useId, useRef, useState } from 'react'\nimport { PROVIDER_PRICING_CHECKED, searchProviderInfo } from './provider-info.ts'\nimport {\n WEB_SEARCH_RPC_CHANNEL, pickActiveSearch, resolveSearchOrder,\n type ProviderView, type RpcResult, type WebSettings, type WebStatus,\n} from './contracts.ts'\n\nexport const name = 'dsh-web-search-manager-client'\nexport const inject = ['slots', 'connection', 'remote', 'remote.credentials'] as const\n\ninterface Credentials {\n describe(refs: string[]): Promise<RpcResult<Record<string, { configured: boolean; writable: boolean; source?: string }>>>\n set(ref: string, value: string): Promise<RpcResult<unknown>>\n unset(ref: string): Promise<RpcResult<unknown>>\n}\ninterface Client {\n connection: { rpc: { call(channel: string, endpoint: string, payload: unknown): Promise<unknown> } }\n remote: { credentials: Credentials }\n slots: {\n inject(key: string, callback: () => unknown): () => void\n register(spec: { name: string; key: string }, render: unknown): () => void\n }\n}\n\nfunction unwrap<T>(result: RpcResult<T>): T {\n if (!result.ok) throw new Error(result.error.message)\n return result.value\n}\nfunction editable(settings: WebSettings): Omit<WebSettings, 'revision'> {\n const { revision: _revision, ...rest } = settings\n return rest\n}\n\nexport function isProviderOn(status: WebStatus, provider: ProviderView): boolean {\n const enabled = provider.kind === 'search' ? status.searchActive : status.fetchActive\n const selected = status.settings[provider.kind === 'search' ? 'searchProvider' : 'fetchProvider']\n return enabled && selected === provider.id\n}\n\nexport function searchBackends(status: WebStatus): ProviderView[] {\n const all = status.providers.filter(provider => provider.kind === 'search')\n const order = resolveSearchOrder(\n all.map(provider => provider.id),\n status.settings,\n id => Boolean(all.find(provider => provider.id === id)?.credentialRef),\n )\n return order.flatMap(id => all.find(provider => provider.id === id) ?? [])\n}\n\nexport function catalogSearchBackends(status: WebStatus): ProviderView[] {\n const enabled = searchBackends(status)\n const rest = status.providers.filter(provider => provider.kind === 'search' && !enabled.some(row => row.id === provider.id))\n return [...enabled, ...rest]\n}\n\nexport function selectedSearchBackend(status: WebStatus): ProviderView | undefined {\n const backends = searchBackends(status)\n const id = pickActiveSearch(backends.map(provider => provider.id), id => Boolean(backends.find(provider => provider.id === id)?.configured))\n return backends.find(provider => provider.id === id)\n}\n\nfunction ExternalLink({ url, label, children }: { url: string; label: string; children: string }) {\n return <a href={url} target=\"_blank\" rel=\"noreferrer noopener\" aria-label={label}\n onClick={event => {\n const bridge = (globalThis as { dshWindow?: { openExternal?(url: string): void } }).dshWindow\n if (bridge?.openExternal) {\n event.preventDefault()\n bridge.openExternal(url)\n }\n }}>{children}</a>\n}\n\nexport function canEnableSearch(\n order: readonly string[],\n providers: readonly ProviderView[],\n keys: Record<string, string>,\n writable: Record<string, boolean>,\n): boolean {\n return order.some(id => {\n const provider = providers.find(item => item.kind === 'search' && item.id === id)\n if (!provider) return false\n if (provider.configured) return true\n const typed = (keys[provider.id] ?? '').trim()\n return Boolean(provider.credentialRef && typed && writable[provider.credentialRef] !== false)\n })\n}\n\nexport function nextSearchEnabled(\n currentlyEnabled: boolean,\n nextOrder: readonly string[],\n providers: readonly ProviderView[],\n keys: Record<string, string>,\n writable: Record<string, boolean>,\n): boolean {\n return currentlyEnabled && canEnableSearch(nextOrder, providers, keys, writable)\n}\n\nfunction ConfirmButton(props: { label: string; confirmLabel: string; disabled?: boolean; onConfirm(): void }) {\n const [armed, setArmed] = useState(false)\n const timer = useRef<ReturnType<typeof setTimeout>>(undefined)\n useEffect(() => () => clearTimeout(timer.current), [])\n function disarm() {\n clearTimeout(timer.current)\n setArmed(false)\n }\n return <button type=\"button\" className=\"web-search-danger\" disabled={props.disabled}\n onClick={() => {\n if (!armed) {\n setArmed(true)\n timer.current = setTimeout(() => setArmed(false), 3000)\n return\n }\n disarm()\n props.onConfirm()\n }}\n onBlur={disarm}>{armed ? props.confirmLabel : props.label}</button>\n}\n\nexport function NetworkSearchSettings({ client }: { client: Client }) {\n const tabsId = useId()\n const [tab, setTab] = useState<'providers' | 'limits'>('providers')\n const [status, setStatus] = useState<WebStatus>()\n const [draft, setDraft] = useState<WebSettings>()\n const [keys, setKeys] = useState<Record<string, string>>({})\n const [busy, setBusy] = useState(false)\n const [dragSource, setDragSource] = useState<string | null>(null)\n const [dropTarget, setDropTarget] = useState<string | null>(null)\n const [sortAnnouncement, setSortAnnouncement] = useState('')\n const [note, setNote] = useState('')\n const [error, setError] = useState('')\n const [writable, setWritable] = useState<Record<string, boolean>>({})\n\n async function call<T>(endpoint: string, payload: unknown = {}): Promise<T> {\n return unwrap(await client.connection.rpc.call(WEB_SEARCH_RPC_CHANNEL, endpoint, payload) as RpcResult<T>)\n }\n async function load() {\n const next = await call<WebStatus>('status')\n setStatus(next); setDraft(next.settings)\n const refs = next.providers.flatMap(provider => provider.credentialRef ? [provider.credentialRef] : [])\n if (refs.length) {\n const credentials = unwrap(await client.remote.credentials.describe(refs))\n setWritable(Object.fromEntries(Object.entries(credentials).map(([ref, value]) => [ref, value.writable])))\n }\n return next\n }\n useEffect(() => { void load().catch(() => setError('无法读取网络搜索设置,请检查 Host 连接后重试。')) }, [client])\n\n async function action(run: () => Promise<void>) {\n setBusy(true); setNote(''); setError('')\n try { await run() }\n catch (cause) { setError(cause instanceof Error ? cause.message : '操作失败。'); await load().catch(() => {}) }\n finally { setBusy(false) }\n }\n async function update(settings: Omit<WebSettings, 'revision'>, expectedRevision: number) {\n const next = await call<WebStatus>('update', { settings, expectedRevision })\n setStatus(next); setDraft(next.settings)\n return next\n }\n\n async function persist(on: boolean, order: string[]) {\n if (!status || !draft) return\n for (const provider of status.providers) {\n if (provider.kind !== 'search') continue\n const snapshot = keys[provider.id] ?? ''\n const typed = snapshot.trim()\n if (!provider.credentialRef || !typed) continue\n if (writable[provider.credentialRef] === false) throw new Error('当前凭据为只读,无法写入。')\n unwrap(await client.remote.credentials.set(provider.credentialRef, typed))\n setKeys(current => current[provider.id] === snapshot ? { ...current, [provider.id]: '' } : current)\n }\n const bounded = (key: (typeof limits)[number][0]) => {\n const row = limits.find(item => item[0] === key)!\n return Math.min(row[3], Math.max(row[2], Number.isFinite(draft[key]) ? draft[key] : row[2]))\n }\n await update({\n ...editable(status.settings),\n maxResults: bounded('maxResults'), maxQueries: bounded('maxQueries'),\n timeoutMs: bounded('timeoutMs'), maxFetchChars: bounded('maxFetchChars'),\n endpoints: draft.endpoints, searchOrder: order,\n searchEnabled: on, fetchProvider: 'http', fetchEnabled: on,\n }, status.settings.revision)\n await load()\n }\n\n async function removeKey(provider: ProviderView) {\n if (!provider.credentialRef || provider.credentialShared || !status) return\n unwrap(await client.remote.credentials.unset(provider.credentialRef))\n setKeys(current => ({ ...current, [provider.id]: '' }))\n await load()\n setNote('已删除 Key。')\n }\n\n if (!status || !draft) {\n return <section className=\"web-search-settings\">\n <p role=\"status\">{error || '正在读取设置…'}</p>\n {error ? <button type=\"button\" onClick={() => void action(async () => { await load() })}>重新连接</button> : null}\n </section>\n }\n\n const enabled = searchBackends(status)\n const backends = catalogSearchBackends(status)\n const selected = selectedSearchBackend(status)\n const on = status.settings.searchEnabled\n const order = enabled.map(provider => provider.id)\n const canEnable = canEnableSearch(order, status.providers, keys, writable)\n const limits = [\n ['maxResults', '每条查询的结果上限', 1, 20],\n ['maxQueries', '每次工具调用的查询上限', 1, 5],\n ['timeoutMs', '请求超时(毫秒)', 1000, 120000],\n ['maxFetchChars', '网页正文字符上限', 1000, 200000],\n ] as const\n\n function move(id: string, nextIndex: number) {\n const index = order.indexOf(id)\n if (busy || index < 0 || nextIndex < 0 || nextIndex >= order.length || index === nextIndex) return\n const next = [...order]\n const [item] = next.splice(index, 1)\n next.splice(nextIndex, 0, item)\n void action(async () => {\n await persist(on, next)\n setSortAnnouncement((backends.find(provider => provider.id === id)?.label ?? id) + ' 已移至第 ' + (nextIndex + 1) + ' 位')\n })\n }\n\n function endDrag() {\n setDragSource(null)\n setDropTarget(null)\n }\n\n return <section className=\"web-search-settings\" data-testid=\"web-search-settings\">\n <div className=\"web-search-tabs\" role=\"tablist\" aria-label=\"网络搜索设置\" onKeyDown={event => {\n if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) return\n const buttons = [...event.currentTarget.querySelectorAll<HTMLButtonElement>('[role=\"tab\"]')]\n const index = buttons.indexOf(event.target as HTMLButtonElement)\n if (index < 0) return\n event.preventDefault()\n const next = event.key === 'Home' ? 0 : event.key === 'End' ? buttons.length - 1\n : (index + (event.key === 'ArrowRight' ? 1 : -1) + buttons.length) % buttons.length\n buttons[next]?.focus()\n buttons[next]?.click()\n }}>\n {([['providers', '搜索服务'], ['limits', '请求限制']] as const).map(([key, label]) => (\n <button key={key} type=\"button\" role=\"tab\" id={tabsId + '-' + key + '-tab'}\n aria-controls={tabsId + '-' + key + '-panel'} aria-selected={tab === key}\n tabIndex={tab === key ? 0 : -1} onClick={() => setTab(key)}>{label}</button>\n ))}\n </div>\n <span className=\"web-search-sr-only\" role=\"status\" aria-live=\"polite\">{sortAnnouncement}</span>\n {error && <p role=\"alert\" className=\"web-search-error\">{error}</p>}\n {note && <p role=\"status\">{note}</p>}\n {status.storageFailed && <p role=\"alert\">配置保存异常,当前运行已暂停网络访问。请重新保存。</p>}\n <div role=\"tabpanel\" id={tabsId + '-providers-panel'} aria-labelledby={tabsId + '-providers-tab'}\n hidden={tab !== 'providers'} tabIndex={0}>\n {backends.length === 0 ? <p className=\"web-search-empty\">还没有可用的搜索后端。</p> : <article\n className=\"web-search-card\"\n data-testid=\"web-search-tool\"\n data-on={on ? 'true' : 'false'}>\n <header>\n <div>\n <h3>联网搜索</h3>\n {!canEnable && <p className=\"web-search-meta\">请选择搜索服务并配置 Key。</p>}\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n className={`web-search-switch${on ? ' is-on' : ''}`}\n aria-checked={on}\n aria-label={on ? '关闭联网搜索' : '启用联网搜索'}\n disabled={busy || (!on && !canEnable)}\n onClick={() => void action(() => persist(!on, order))}>\n <span className=\"web-search-switch-thumb\" aria-hidden=\"true\" />\n </button>\n </header>\n <ol className=\"web-search-rank\" aria-label=\"搜索后端\">\n {backends.map(provider => {\n const participating = order.includes(provider.id)\n const rank = order.indexOf(provider.id)\n const active = status.searchActive && selected?.id === provider.id\n const info = searchProviderInfo(provider)\n const needsKey = Boolean(provider.credentialRef)\n const shared = Boolean(provider.credentialShared)\n const showKey = needsKey && participating && (!shared || !provider.configured)\n const canSort = participating && order.length > 1\n return <li key={provider.id} className={active ? 'is-active' : undefined} data-testid={`web-search-rank-${provider.id}`}\n data-dragging={dragSource === provider.id || undefined}\n data-drop={dropTarget === provider.id && dragSource ? (order.indexOf(dragSource) < rank ? 'after' : 'before') : undefined}\n onDragOver={event => {\n if (busy || !canSort || !dragSource || dragSource === provider.id) return\n event.preventDefault()\n event.dataTransfer.dropEffect = 'move'\n setDropTarget(provider.id)\n }}\n onDragLeave={event => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setDropTarget(null)\n }}\n onDrop={event => {\n if (busy || !canSort || !dragSource) return\n event.preventDefault()\n move(dragSource, rank)\n endDrag()\n }}>\n {canSort ? <button type=\"button\" className=\"web-search-drag-handle\"\n draggable={!busy} aria-disabled={busy}\n aria-label={'拖动排序 ' + provider.label}\n title=\"拖动排序,或用上下方向键调整\"\n onDragStart={event => {\n if (busy) { event.preventDefault(); return }\n event.dataTransfer.effectAllowed = 'move'\n event.dataTransfer.setData('application/x-dsh-search-provider', provider.id)\n const row = event.currentTarget.closest('li')\n if (row) event.dataTransfer.setDragImage(row, 16, 16)\n setDragSource(provider.id)\n setSortAnnouncement('')\n }}\n onDragEnd={endDrag}\n onKeyDown={event => {\n if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return\n event.preventDefault()\n move(provider.id, rank + (event.key === 'ArrowUp' ? -1 : 1))\n }}>\n <svg width=\"16\" height=\"20\" viewBox=\"0 0 16 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <circle cx=\"5\" cy=\"5\" r=\"1.5\" /><circle cx=\"11\" cy=\"5\" r=\"1.5\" />\n <circle cx=\"5\" cy=\"10\" r=\"1.5\" /><circle cx=\"11\" cy=\"10\" r=\"1.5\" />\n <circle cx=\"5\" cy=\"15\" r=\"1.5\" /><circle cx=\"11\" cy=\"15\" r=\"1.5\" />\n </svg>\n </button> : <span className=\"web-search-rank-index\">{participating ? rank + 1 : '—'}</span>}\n <div className=\"web-search-provider\">\n <div className=\"web-search-provider-heading\">\n <strong>{provider.label}</strong>\n {active && <span className=\"web-search-meta\">当前使用</span>}\n {provider.signupUrl && <ExternalLink url={provider.signupUrl} label={provider.label + ' 去注册'}>去注册</ExternalLink>}\n </div>\n <div className=\"web-search-provider-info\">\n <p>{info.description}</p>\n <details>\n <summary>费用说明</summary>\n <p>{info.pricing}{info.pricingUrl && <> <ExternalLink url={info.pricingUrl}\n label={provider.label + ' 费用说明'}>{provider.id === 'ddg' ? '官网' : '费用说明'}</ExternalLink></>}</p>\n </details>\n </div>\n {participating && !provider.configured && <p className=\"web-search-meta\">{needsKey ? '待配置 Key' : '暂不可用'}</p>}\n {shared && participating && <small>{provider.credentialHint ?? '与其他设置共用凭据'}</small>}\n {showKey ? <label>API Key\n <input type=\"password\" autoComplete=\"off\" spellCheck={false}\n disabled={busy || writable[provider.credentialRef ?? ''] === false}\n value={keys[provider.id] ?? ''}\n placeholder={provider.configured ? '已配置,留空不替换' : '请输入 API Key'}\n onChange={event => setKeys(current => ({ ...current, [provider.id]: event.target.value }))} />\n </label> : null}\n {needsKey && !shared && provider.configured ? <ConfirmButton\n disabled={busy || writable[provider.credentialRef ?? ''] === false}\n label=\"删除 Key\" confirmLabel=\"确认删除 Key?\"\n onConfirm={() => void action(() => removeKey(provider))} /> : null}\n </div>\n <div className=\"web-search-rank-move\">\n <button\n type=\"button\"\n role=\"switch\"\n className={`web-search-switch${participating ? ' is-on' : ''}`}\n aria-checked={participating}\n aria-label={`${participating ? '关闭' : '开启'} ${provider.label}`}\n disabled={busy}\n onClick={() => {\n const next = participating ? order.filter(id => id !== provider.id) : [...order, provider.id]\n void action(() => persist(nextSearchEnabled(status.settings.searchEnabled, next, status.providers, keys, writable), next))\n }}>\n <span className=\"web-search-switch-thumb\" aria-hidden=\"true\" />\n </button>\n </div>\n </li>\n })}\n </ol>\n <p className=\"web-search-meta\">价格核对于 {PROVIDER_PRICING_CHECKED},实际额度与费用以供应商账户为准。</p>\n {on ? <div className=\"web-search-card-actions\">\n <button type=\"button\" disabled={busy} onClick={() => void action(async () => {\n await persist(status.settings.searchEnabled, order)\n const result = await call<{ sources: number }>('test')\n await load()\n setNote(`连接正常,返回 ${result.sources} 条来源。`)\n })}>测试连接(可能计费)</button>\n </div> : null}\n </article>}\n </div>\n <div role=\"tabpanel\" id={tabsId + '-limits-panel'} aria-labelledby={tabsId + '-limits-tab'}\n hidden={tab !== 'limits'} tabIndex={0}>\n <fieldset className=\"web-search-limits\" disabled={busy} aria-label=\"请求限制\">\n {limits.map(([key, label, min, max]) => (\n <label key={key}>{label}\n <input type=\"number\" min={min} max={max} step={1} value={draft[key]}\n onChange={event => setDraft({ ...draft, [key]: Number(event.target.value) })} />\n </label>\n ))}\n </fieldset>\n </div>\n <button type=\"button\" disabled={busy} onClick={() => void action(async () => {\n await persist(status.settings.searchEnabled, order)\n setNote('已保存。')\n })}>保存</button>\n </section>\n}\n\nconst styles = `\n.web-search-settings{max-width:760px;display:grid;gap:24px;color:inherit;font:400 var(--font-size-2,14px)/1.5 var(--default-font-family,system-ui,sans-serif)}\n.web-search-settings p{margin:0;line-height:1.5}\n.web-search-settings small,.web-search-meta,.web-search-empty{font-size:var(--font-size-1,13px);color:var(--gray-11,inherit)}\n.web-search-error{color:var(--red-11,#b42318)}\n.web-search-card{display:grid;gap:12px;padding:16px;border:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent));border-radius:12px}\n.web-search-card header{display:flex;justify-content:space-between;gap:12px;align-items:center;padding-bottom:8px}\n.web-search-card h3{margin:0;font-size:var(--font-size-3,16px);font-weight:600}\n.web-search-provider{display:grid;gap:8px;min-width:0}\n.web-search-provider-info{display:grid;gap:3px;font-size:var(--font-size-1,13px);color:var(--gray-11,inherit);overflow-wrap:anywhere}\n.web-search-provider-heading{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;min-height:24px}\n.web-search-provider-heading strong{font-weight:500}\n.web-search-card label{display:grid;gap:6px}\n.web-search-settings input{box-sizing:border-box;width:100%;min-width:0;padding:8px 10px;border:1px solid var(--gray-6,color-mix(in srgb,currentColor 22%,transparent));border-radius:8px;background:var(--color-surface,transparent);color:inherit;font:inherit;transition:border-color 150ms ease,box-shadow 150ms ease}\n.web-search-settings input:focus{border-color:var(--accent-9,#3b82f6);box-shadow:0 0 0 2px color-mix(in srgb,var(--accent-9,#3b82f6) 25%,transparent)}\n.web-search-settings button:not([role=\"switch\"]){min-height:34px;padding:6px 12px;border:1px solid color-mix(in srgb,currentColor 25%,transparent);border-radius:8px;background:transparent;color:inherit;cursor:pointer;font:inherit;justify-self:start;transition:background-color 150ms ease,color 150ms ease,border-color 150ms ease,box-shadow 150ms ease,transform 150ms ease}\n.web-search-settings button:not([role=\"switch\"]):not([role=\"tab\"]):not(.web-search-drag-handle):hover:not(:disabled){background:var(--gray-3,color-mix(in srgb,currentColor 6%,transparent));border-color:color-mix(in srgb,currentColor 35%,transparent)}\n.web-search-settings button:not([role=\"switch\"]):not([role=\"tab\"]):not(.web-search-drag-handle):active:not(:disabled){transform:scale(.97)}\n.web-search-danger:hover:not(:disabled){border-color:var(--red-11,#b42318);color:var(--red-11,#b42318);background:color-mix(in srgb,var(--red-11,#b42318) 8%,transparent)}\n.web-search-settings button:disabled{opacity:.45;cursor:not-allowed}\n.web-search-tabs{display:flex;gap:20px;border-bottom:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent))}\n.web-search-tabs button[role=\"tab\"]{padding:8px 0;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--gray-11,inherit)}\n.web-search-tabs button[role=\"tab\"]:hover{color:inherit}\n.web-search-tabs button[aria-selected=\"true\"]{border-bottom-color:var(--accent-9,#3b82f6);color:var(--accent-11,inherit);font-weight:600}\n.web-search-settings [role=\"tabpanel\"]{border-radius:12px}\n.web-search-settings .web-search-switch{all:unset;box-sizing:border-box;position:relative;display:inline-block;width:36px;height:20px;flex:none;border-radius:999px;background:var(--gray-7,color-mix(in srgb,currentColor 28%,transparent));cursor:pointer}\n.web-search-switch.is-on{background:var(--accent-9,#3b82f6)}\n.web-search-switch:disabled{cursor:not-allowed;opacity:.7}\n.web-search-switch-thumb{position:absolute;top:3px;left:3px;width:14px;height:14px;border-radius:999px;background:#fff;transition:transform 150ms ease}\n.web-search-switch.is-on .web-search-switch-thumb{transform:translateX(16px)}\n.web-search-settings :focus-visible{outline:2px solid var(--accent-9,currentColor);outline-offset:3px}\n.web-search-card-actions{display:flex;flex-wrap:wrap;gap:8px}\n.web-search-rank{margin:0;padding:0;list-style:none}\n.web-search-rank li{position:relative;display:grid;grid-template-columns:24px minmax(0,1fr) auto;gap:10px;align-items:start;padding:14px 0;border-top:1px solid var(--gray-6,color-mix(in srgb,currentColor 15%,transparent))}\n.web-search-settings button.web-search-drag-handle{display:grid;place-items:center;width:24px;height:24px;min-height:24px;padding:0;border:0;cursor:grab;color:inherit;opacity:.65}\n.web-search-settings button.web-search-drag-handle:hover{opacity:1;background:var(--gray-3,color-mix(in srgb,currentColor 8%,transparent))}\n.web-search-settings button.web-search-drag-handle:active{cursor:grabbing}\n.web-search-settings button.web-search-drag-handle[aria-disabled=\"true\"]{cursor:wait;opacity:.4}\n.web-search-rank li[data-dragging]{opacity:.45}\n.web-search-rank li[data-drop]::after{content:'';position:absolute;left:0;right:0;height:2px;background:var(--accent-9,#3b82f6);pointer-events:none}\n.web-search-rank li[data-drop=\"before\"]::after{top:-1px}\n.web-search-rank li[data-drop=\"after\"]::after{bottom:-1px}\n.web-search-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}\n.web-search-rank-index{opacity:.6;font-variant-numeric:tabular-nums;line-height:24px}\n.web-search-rank-move{display:flex;flex-wrap:wrap;gap:6px;align-items:center;justify-content:flex-end;padding-top:2px}\n.web-search-settings a{color:var(--accent-11,currentColor);font-size:var(--font-size-1,13px);text-underline-offset:3px}\n.web-search-limits{margin:0;border:0;padding:0;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 20px}\n.web-search-limits label{display:grid;gap:6px;font-size:var(--font-size-2,14px)}\n@media(max-width:560px){.web-search-rank-move{flex-direction:column;align-items:flex-end}.web-search-limits{grid-template-columns:minmax(0,1fr)}}\n@media(prefers-reduced-motion:reduce){.web-search-switch-thumb{transition:none}.web-search-settings button:not([role=\"switch\"]),.web-search-settings input{transition:none}}\n`\n\nexport function apply(ctx: Context): void {\n const client = ctx as unknown as Client\n ctx.effect(() => {\n if (typeof document === 'undefined') return () => {}\n const style = document.createElement('style')\n style.setAttribute('data-plugin', '@klarkxy/dsh-web-search-manager'); style.textContent = styles\n style.dataset.dshWebSearch = ''; document.head.appendChild(style)\n return () => style.remove()\n }, 'web-search-manager.styles')\n ctx.effect(() => client.slots.inject('plugins.bundle.config', () => client.slots.register({\n name: 'plugins.bundle.config', key: '@klarkxy/dsh-web-search-manager',\n }, () => <NetworkSearchSettings client={client} />)), 'web-search-manager.settings')\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.inner.cjs","names":["useState","useRef","Button","useCallback","useSyncExternalStore","useId","SegmentedTabs","Switch","Tag","StateDot","Input"],"sources":["../../dsh-plugin-kit/lib/official-ui.js","../src/provider-info.ts","../src/contracts.ts","../src/client.tsx"],"sourcesContent":["//#region src/official-ui.ts\n/**\n* Shared contract that keeps every plugin's browser-side UI on the official\n* DeepSeek Harness Web design language.\n*\n* Two rules produce that language, and both are load-bearing here:\n*\n* 1. Colour, radius, elevation and focus come from the host theme's real\n* `--dsw-*` tokens, written under their own names. Plugins never invent a\n* token, never alias the official ones behind a private palette (a private\n* alias is just a second, diverging theme), and never carries a literal\n* fallback — the host publishes light and dark, and a literal would pin one\n* of them. The only non-colour custom properties used are the host's own\n* content-font axis and frame clearance.\n*\n* 2. Anything the host already ships is used, not reimplemented. Controls come\n* from `@deepseek-ai/dsh-client-ui-primitives` (`Button`, `Input`,\n* `Checkbox`, `Switch`, `Tag`, `Pill`, `SegmentedControl`, `Menu`, `Modal`,\n* `Tooltip`, `Toast`, `DisclosureRow`, `StateDot`, `PathLabel`, the settings\n* form suite). This module only styles what primitives do not cover: page\n* scaffolding, field layout, banners, empty states and scroll regions.\n*\n* The metrics below are transcribed from the primitives' own CSS modules so a\n* feature panel lines up pixel-for-pixel with a native one: the 14/22 body and\n* 13/20 compact type tiers, the 0.5px hairline scale, and the elevation family\n* that draws a surface's edge in its shadow (`border: 0`) instead of a border.\n*/\n/**\n* Every `--dsw-*` token this repo is allowed to reference, grouped by role.\n*\n* Plugins may only colour through this list. It is exported so the guard test\n* can fail a build when a stylesheet reaches for anything else — the failure\n* mode this prevents is silent: an unknown token resolves to nothing, so a\n* border disappears or a label inherits the wrong colour with no error anywhere.\n*/\nconst OFFICIAL_THEME_TOKENS = {\n\t/** Surfaces, from the page up to the topmost nested card. */\n\tsurface: [\n\t\t\"--dsw-alias-bg-base\",\n\t\t\"--dsw-alias-bg-layer-1\",\n\t\t\"--dsw-alias-bg-layer-2\",\n\t\t\"--dsw-alias-bg-layer-3\",\n\t\t\"--dsw-alias-bg-layer-4\",\n\t\t\"--dsw-alias-bg-module-platform\",\n\t\t\"--dsw-alias-bg-overlay\"\n\t],\n\t/** Hairlines. l1 is near-invisible on a menu surface, so menus use l2+. */\n\tborder: [\n\t\t\"--dsw-alias-border-l1\",\n\t\t\"--dsw-alias-border-l2\",\n\t\t\"--dsw-alias-border-l3\",\n\t\t\"--dsw-alias-border-l4\"\n\t],\n\t/** Text. `caption` is menu shortcut text, `dimmed` is placeholder text. */\n\tlabel: [\n\t\t\"--dsw-alias-label-primary\",\n\t\t\"--dsw-alias-label-secondary\",\n\t\t\"--dsw-alias-label-tertiary\",\n\t\t\"--dsw-alias-label-caption\",\n\t\t\"--dsw-alias-label-dimmed\",\n\t\t\"--dsw-alias-label-error\",\n\t\t\"--dsw-alias-label-primary-foreground\"\n\t],\n\t/** Interactive fills. The `-danger` hover belongs to destructive rows. */\n\tinteractive: [\n\t\t\"--dsw-alias-interactive-bg-hover\",\n\t\t\"--dsw-alias-interactive-bg-active\",\n\t\t\"--dsw-alias-interactive-bg-hover-danger\"\n\t],\n\t/** Accent and status. `business` is the focus ring's default colour. */\n\taccent: [\n\t\t\"--dsw-alias-brand-primary\",\n\t\t\"--dsw-alias-button-primary-fill\",\n\t\t\"--dsw-alias-button-primary-hover\",\n\t\t\"--dsw-alias-button-tool-bar-fill\",\n\t\t\"--dsw-alias-button-tool-bar-hover\",\n\t\t\"--dsw-alias-button-ghost-active-fill\",\n\t\t\"--dsw-alias-button-ghost-active-border\"\n\t],\n\tstate: [\n\t\t\"--dsw-alias-state-business-primary\",\n\t\t\"--dsw-alias-state-success-primary\",\n\t\t\"--dsw-alias-state-warn-primary\",\n\t\t\"--dsw-alias-state-error-primary\",\n\t\t\"--dsw-alias-state-idle-primary\"\n\t],\n\t/** Corner scale: sm 8, md 12, lg the large card, panel the modal. */\n\tradius: [\n\t\t\"--dsw-radius-sm\",\n\t\t\"--dsw-radius-md\",\n\t\t\"--dsw-radius-lg\",\n\t\t\"--dsw-radius-panel\"\n\t],\n\t/** An elevated surface draws its edge in the shadow, so it keeps border: 0. */\n\televation: [\n\t\t\"--dsw-elevation-soft\",\n\t\t\"--dsw-elevation-stroke\",\n\t\t\"--dsw-elevation-stroke-color\",\n\t\t\"--dsw-elevation-panel\",\n\t\t\"--dsw-elevation-prominent\"\n\t],\n\t/** Floats, masks and scrollbars. */\n\toverlay: [\n\t\t\"--dsw-menu-surface-fill\",\n\t\t\"--dsw-menu-backdrop-filter\",\n\t\t\"--dsw-mask-blur\",\n\t\t\"--dsw-alias-bg-mask-1\",\n\t\t\"--dsw-alias-menu-icon\",\n\t\t\"--dsw-alias-scrollbar-bg-l2\",\n\t\t\"--dsw-alias-scrollbar-hover-l2\",\n\t\t\"--dsw-shadow-lv3\"\n\t],\n\t/** Motion, focus and type axis, published by the host rather than by a component. */\n\tsystem: [\n\t\t\"--dsw-focus-ring-width\",\n\t\t\"--dsw-focus-ring-color\",\n\t\t\"--dsw-font-markdown-code-font-family\",\n\t\t\"--ds-transition-duration\",\n\t\t\"--ds-ease-in-out\",\n\t\t\"--ds-font-family-code\",\n\t\t\"--dsh-scrollbar-thumb\",\n\t\t\"--dsh-scrollbar-thumb-hover\",\n\t\t\"--dsh-content-font-size-secondary\",\n\t\t\"--dsh-content-font-delta\",\n\t\t\"--dsh-frame-top-clearance\"\n\t]\n};\n/** Every official token name, flat. Used by the token guard test. */\nconst OFFICIAL_THEME_TOKEN_NAMES = Object.values(OFFICIAL_THEME_TOKENS).flat();\n/**\n* The host's focus ring shorthand, verbatim. Writing this per control is how\n* rings drift apart; a stylesheet that draws its own focus style should use\n* {@link officialFocus} instead. The colour fallback is the host's own default.\n*/\nconst OFFICIAL_FOCUS_RING = \"var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary))\";\n/**\n* A complete `outline` declaration at the official geometry. `offset` defaults\n* to the 2px the native controls use; the host's inline field rules sit at 1px\n* and a segmented tab pulls the ring inside itself at -2px.\n*/\nfunction officialFocus(offset = \"2px\") {\n\treturn `outline: ${OFFICIAL_FOCUS_RING}; outline-offset: ${offset}`;\n}\n/**\n* An elevated surface. The host draws a raised surface's edge inside its\n* shadow rather than as a border, so a card sets `border: 0` and takes the edge\n* from the elevation — which is also why its border stays off the alias-border\n* set that a flat, non-elevated rule would use.\n*/\nfunction officialElevation(level) {\n\treturn `border: 0; box-shadow: var(--dsw-elevation-${level})`;\n}\n/**\n* An elevated surface whose edge should read as a specific hairline. Rebinding\n* the stroke colour is how a menu card picks l1 while a panel picks l3, without\n* the two growing apart by hand.\n*/\nfunction officialStrokedElevation(level, color) {\n\treturn `--dsw-elevation-stroke-color: ${color}; ${officialElevation(level)}`;\n}\n/**\n* The shared stylesheet for a plugin UI, scoped under that plugin's root class.\n*\n* Scoping is what keeps this safe to always-bundle into every client: the rules\n* can only match inside the plugin's own subtree, so two plugins can both mount\n* `dsh-ui-card` without either styling the other's markup.\n*\n* Each recipe matches the root element *and* its descendants, because the\n* commonest arrangement is one element that is both — a surface that carries\n* the root class and `dsh-ui-card`, or a portaled dialog that is the root and\n* the `dsh-ui-surface`. A descendant-only scope would silently leave those\n* unstyled, with no error anywhere.\n*\n* A caveat worth knowing: `Modal` and `Menu` portal to `document.body`, so their\n* content leaves the plugin's subtree entirely. A portaled surface therefore\n* needs its own root class on an element inside the portal.\n*\n* Only patterns that primitives do not provide live here. If a control appears\n* below that `Button`/`Input`/`Switch`/`Tag`/`Menu` already covers, that is a\n* bug in this file: use the primitive and delete the recipe.\n*/\nfunction officialUiCss(roots) {\n\tconst scope = (typeof roots === \"string\" ? [roots] : roots).map((root) => `.${root}`).join(\", \");\n\treturn `\n/* Official DSH Web UI contract. Generated by @klarkxy/dsh-plugin-kit/official-ui.\n * Do not hand-edit the copy inside a plugin: change this module so every plugin\n * moves together. Scope: ${scope} */\n/* The scope rule below stays open for the whole sheet: every rule after it\n * nests with the parent selector, so one stylesheet can cover several unrelated\n * roots without leaking into a neighbouring plugin. Its closing brace is last. */\n${scope} {\n color: var(--dsw-alias-label-primary);\n font-family: inherit;\n font-size: 14px;\n line-height: 22px;\n min-width: 0;\n\n& *, & *::before, & *::after { box-sizing: border-box; }\n& h1, & h2, & h3, & h4, & p, & figure { margin: 0; }\n/* Keyboard focus only: pointer input keeps the native resting appearance. The\n * ring needs no radius of its own — the outline already follows the control's\n * own border-radius, and overriding it here would flatten every control. */\n& :focus-visible { ${officialFocus()}; }\n& [hidden] { display: none !important; }\n\n/* --- Type tiers. The same 14/22 and 13/20 steps the primitives use. --- */\n& .dsh-ui-title { font-size: 16px; line-height: 24px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-heading { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-compact { font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-meta { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-secondary); }\n& .dsh-ui-hint { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-error { font-size: 12px; line-height: 18px; color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-warn { color: var(--dsw-alias-state-warn-primary); }\n& .dsh-ui-success { color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-muted { color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-truncate { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n& .dsh-ui-wrap { min-width: 0; overflow-wrap: anywhere; }\n\n/* --- Layout scaffolding. --- */\n& .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }\n& .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }\n& .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }\n& .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }\n& .dsh-ui-spacer { flex: 1; min-width: 0; }\n/* A 0.5px l2 rule is the host's section divider; reserve the same rhythm. */\n& .dsh-ui-divider { height: 0.5px; background: var(--dsw-alias-border-l2); }\n& .dsh-ui-section { display: flex; flex-direction: column; gap: 12px; padding-top: 16px; border-top: 0.5px solid var(--dsw-alias-border-l2); }\n\n/* --- Card: a raised surface whose edge lives in the shadow. --- */\n& .dsh-ui-card {\n ${officialElevation(\"stroke\")}\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n min-width: 0;\n}\n& .dsh-ui-card--flat { border: 0.5px solid var(--dsw-alias-border-l3); box-shadow: none; }\n& .dsh-ui-card--nested { background: var(--dsw-alias-bg-layer-2); }\n& .dsh-ui-card--plain { background: none; }\n\n/* --- Field: label, control, help, error. The control itself is an\n * official primitive, so this only owns the vertical rhythm. --- */\n& .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }\n& .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }\n& .dsh-ui-label { display: flex; align-items: center; gap: 6px; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n& .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }\n& .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }\n& .dsh-ui-help p { margin: 0; }\n& .dsh-ui-help p + p { margin-top: 8px; }\n& .dsh-ui-required { color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-control { width: 100%; min-width: 0; }\n/* An invalid control is marked on the control, not only in the message. */\n& .dsh-ui-control[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-readonly { display: flex; flex-direction: column; gap: 4px; min-width: 0; }\n& .dsh-ui-readonly > dt { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n& .dsh-ui-readonly > dd { margin: 0; font-size: 13px; line-height: 20px; overflow-wrap: anywhere; }\n\n/* --- Buttons row. A no-op container: it exists so actions line up on the\n * trailing edge the way every native panel does. --- */\n& .dsh-ui-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-top: 4px; }\n& .dsh-ui-actions-end { justify-content: flex-end; }\n\n/* --- Banners. A banner is a left-rail notice, the shape used for warnings,\n * deprecations and blocking instructions. --- */\n& .dsh-ui-banner {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px 14px;\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-left: 3px solid var(--dsw-alias-state-warn-primary);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n& .dsh-ui-banner-title { font-weight: 500; color: var(--dsw-alias-state-warn-primary); }\n& .dsh-ui-banner--info { border-left-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-banner--danger { border-left-color: var(--dsw-alias-state-error-primary); }\n& .dsh-ui-banner--success { border-left-color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-banner p { margin: 0; }\n\n/* --- Inline notice: a transient confirmation with no chrome of its own. --- */\n& .dsh-ui-notice { display: flex; align-items: center; gap: 6px; font-size: 12px; line-height: 18px; color: var(--dsw-alias-state-success-primary); }\n& .dsh-ui-notice--error { color: var(--dsw-alias-state-error-primary); }\n\n/* --- Empty and loading states. Both sit in a dashed well so an empty panel\n * reads as \"nothing here yet\" rather than as a broken layout. --- */\n& .dsh-ui-empty {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n padding: 20px 16px;\n border: 0.5px dashed var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n& .dsh-ui-loading { display: flex; align-items: center; gap: 8px; padding: 20px 0; font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-secondary); }\n\n/* --- Selectable list. A row is a button-sized target with a hover fill and\n * a selected fill; the name carries the weight, the description does not. --- */\n& .dsh-ui-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; min-width: 0; }\n& .dsh-ui-list-scroll { max-height: min(66vh, 760px); overflow-y: auto; overflow-x: hidden; }\n& .dsh-ui-list-row { border-radius: var(--dsw-radius-md); }\n& .dsh-ui-list-row:hover { background: var(--dsw-alias-interactive-bg-hover); }\n& .dsh-ui-list-row[aria-selected='true'], & .dsh-ui-list-row[data-selected] { background: var(--dsw-alias-interactive-bg-active); }\n& .dsh-ui-list-item {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n width: 100%;\n min-width: 0;\n padding: 10px 12px;\n border: 0;\n border-radius: var(--dsw-radius-md);\n background: none;\n font: inherit;\n color: inherit;\n text-align: start;\n cursor: pointer;\n}\n& .dsh-ui-list-item:disabled { cursor: default; }\n& .dsh-ui-list-item:disabled:hover { background: none; }\n& .dsh-ui-list-name { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); overflow-wrap: anywhere; }\n& .dsh-ui-list-desc { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }\n\n/* --- Code and structured output. Wraps rather than scrolls, because a\n * feature panel is read rather than scanned. --- */\n& .dsh-ui-code {\n padding: 10px 12px;\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-1);\n font-family: var(--ds-font-family-code, ui-monospace, 'Cascadia Mono', Consolas, monospace);\n font-size: 12px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n overflow-wrap: anywhere;\n white-space: pre-wrap;\n}\n& .dsh-ui-scroll { max-height: 60vh; overflow: auto; overscroll-behavior: contain; }\n\n/* --- A toggle row: label on the left, switch on the trailing edge. This is\n * layout only; the switch itself is the official primitive. --- */\n& .dsh-ui-toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-width: 0; padding: 12px 0; }\n& .dsh-ui-toggle-row + .dsh-ui-toggle-row { border-top: 0.5px solid var(--dsw-alias-border-l2); }\n& .dsh-ui-toggle-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }\n& .dsh-ui-toggle-label { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n\n/* --- Floating surface: a panel anchored to a trigger. This is the material\n * a menu card is made of — the translucent fill plus its backdrop blur, with\n * the edge riding inside the prominent elevation. A plugin that hand-rolls this\n * is how tokens like --dsw-specific-menu get invented; use this instead. --- */\n& .dsh-ui-surface {\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);\n --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);\n position: relative;\n display: flex;\n flex-direction: column;\n border: 0;\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-menu-surface-fill);\n backdrop-filter: var(--dsw-menu-backdrop-filter);\n box-shadow: var(--dsw-elevation-prominent);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n line-height: 20px;\n min-width: 0;\n}\n& .dsh-ui-surface-body { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px 14px; overflow-y: auto; }\n& .dsh-ui-surface-head { display: flex; align-items: center; gap: 8px; min-width: 0; }\n& .dsh-ui-surface-title { font-size: 14px; line-height: 22px; font-weight: 500; color: var(--dsw-alias-label-primary); }\n\n/* --- Native select. The primitives ship no select, so a plugin that offers a\n * closed list of choices keeps the platform control and matches the official\n * settings field geometry exactly (34px, 0.5px l4, radius-md, layer-3). A\n * SegmentedControl is the primitive to reach for when the choices are few\n * enough to show at once. --- */\n& .dsh-ui-select {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n height: 34px;\n padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n& .dsh-ui-select:focus-visible { outline: none; border-color: var(--dsw-alias-state-business-primary); }\n& .dsh-ui-select:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n& .dsh-ui-select[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }\n\n/* Long panels scroll inside themselves instead of growing the host page. */\n& .dsh-ui-panel { display: flex; flex-direction: column; gap: 16px; min-width: 0; }\n& .dsh-ui-panel-wide { max-width: 100%; }\n\n@media (prefers-reduced-motion: reduce) {\n & *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }\n}\n}\n`.replace(/^& (\\.dsh-ui-[a-z0-9-]+)(?![+>~])/gm, (_match, className) => `&${className}, & ${className}`);\n}\n//#endregion\nexport { OFFICIAL_FOCUS_RING, OFFICIAL_THEME_TOKENS, OFFICIAL_THEME_TOKEN_NAMES, officialElevation, officialFocus, officialStrokedElevation, officialUiCss };\n\n//# sourceMappingURL=official-ui.js.map","import type { ProviderView } from './contracts.ts'\n\n// Public prices checked on 2026-09-21; links remain available for current account terms.\nexport const PROVIDER_PRICING_CHECKED = '2026-09-21'\n\ninterface ProviderInfo {\n description: string\n pricing: string\n pricingUrl?: string\n}\n\nconst providerInfo: Record<string, ProviderInfo> = {\n ddg: {\n description: '搜索 DuckDuckGo 公开网页,无需注册或 API Key。',\n pricing: '免费使用,不产生搜索 API 费用。',\n pricingUrl: 'https://duckduckgo.com/',\n },\n bocha: {\n description: '面向中文内容的网页搜索,返回标题、链接和摘要。',\n pricing: '按调用次数计费,目录价 ¥0.036/次;试用额度以官方活动为准。',\n pricingUrl: 'https://aq6ky2b8nql.feishu.cn/wiki/JYSbwzdPIiFnz4kDYPXcHSDrnZb',\n },\n brave: {\n description: '使用 Brave 独立网页索引,搜索网页、新闻等内容。',\n pricing: '每月赠 $5(约 1,000 次);超出 $5/千次,激活需绑卡。',\n pricingUrl: 'https://brave.com/search/api/',\n },\n 'deepseek-official': {\n description: '由 DeepSeek 模型调用内置搜索,复用模型 API Key。',\n pricing: '默认 Flash 按 tokens 计费:每百万输入 ¥1–2(缓存命中 ¥0.02–0.04)、输出 ¥4–8,随峰谷时段变化;赠送余额与工具费用以平台为准。',\n pricingUrl: 'https://api-docs.deepseek.com/zh-cn/quick_start/pricing/',\n },\n exa: {\n description: '面向 AI 的网页搜索,提供相关网页与内容片段。',\n pricing: '注册赠 $20,之后每月赠 $10;$7/千次(每次最多 10 条),超出 10 条每条加 $1/千次。',\n pricingUrl: 'https://exa.ai/pricing',\n },\n firecrawl: {\n description: '搜索网页,并可配合网页内容提取。',\n pricing: '每月免费 1,000 积分,搜索每 10 条结果扣 2 积分;Hobby 含 5,000 积分/月,年付折合 $16/月,额外 $5/千积分。',\n pricingUrl: 'https://www.firecrawl.dev/pricing',\n },\n serper: {\n description: '获取 Google 的网页搜索结果。',\n pricing: '注册赠 2,500 次(一次性);充值 $50/5万次($1/千次),付费额度有效期 6 个月。',\n pricingUrl: 'https://serper.dev/',\n },\n tavily: {\n description: '面向 AI 的网页搜索,当前使用基础搜索。',\n pricing: '每月免费 1,000 积分,基础搜索 1 积分/次;按量付费 $0.008/积分($8/千次)。',\n pricingUrl: 'https://docs.tavily.com/documentation/api-credits',\n },\n}\n\nexport function searchProviderInfo(provider: ProviderView): ProviderInfo {\n const known = Object.hasOwn(providerInfo, provider.id) ? providerInfo[provider.id] : undefined\n return {\n description: known?.description ?? provider.description,\n pricing: provider.pricing ?? known?.pricing ?? (provider.billing === 'none' ? '该后端不收取搜索费用。'\n : provider.billing === 'model-and-tools' ? '按模型用量与工具调用计费;额度与单价见供应商说明。'\n : '按 API 调用计费;额度与单价见供应商说明。'),\n pricingUrl: provider.pricingUrl ?? known?.pricingUrl ?? provider.signupUrl,\n }\n}\n","import type { WebFetchProvider, WebSearchProvider } from '@deepseek-ai/dsh-web'\n\nexport const WEB_SEARCH_RPC_CHANNEL = '/web-search-manager'\nexport type RpcResult<T = unknown> = { ok: true; value: T } | {\n ok: false; error: { code: string; message: string; details: Record<string, unknown> }\n}\nexport type ProviderKind = 'search' | 'fetch'\n/** Management metadata only. Execution and source vocabulary belong to ctx.web. */\nexport interface ProviderDescriptor {\n readonly id: string\n readonly label: string\n readonly description: string\n readonly defaultBaseURL?: string\n readonly credentialRef?: string\n /** True when the key is shared with another surface. The page must not delete it. */\n readonly credentialShared?: boolean\n /** Optional notice naming the settings surface that owns a shared credential. */\n readonly credentialHint?: string\n readonly billing: 'request' | 'model-and-tools' | 'none'\n /** Optional provider-supplied billing summary. */\n readonly pricing?: string\n /** Public HTTPS page explaining provider charges. */\n readonly pricingUrl?: string\n /** Public HTTPS page where the user can create an API key. */\n readonly signupUrl?: string\n}\nexport interface ProviderOptions {\n readonly apiKey?: string\n readonly baseURL?: string\n readonly timeoutMs: number\n readonly maxFetchChars: number\n}\nexport type SearchProviderFactory = (options: ProviderOptions) => WebSearchProvider\nexport type FetchProviderFactory = (options: ProviderOptions) => WebFetchProvider\n/** Never store credential values here. Keys are resolved by reference per call. */\nexport interface WebSettings {\n revision: number\n searchEnabled: boolean\n fetchEnabled: boolean\n searchProvider: string\n fetchProvider: string\n searchOrder: string[]\n maxResults: number\n maxQueries: number\n timeoutMs: number\n maxFetchChars: number\n endpoints: Record<string, string>\n}\nexport const DEFAULT_SEARCH_ORDER = ['ddg'] as const\n\nexport const defaultSettings = (): WebSettings => ({\n revision: 0, searchEnabled: true, fetchEnabled: true,\n searchProvider: 'ddg', fetchProvider: 'http', searchOrder: [...DEFAULT_SEARCH_ORDER],\n maxResults: 5, maxQueries: 1,\n timeoutMs: 30_000, maxFetchChars: 100_000, endpoints: {},\n})\n\n/** Keyed backends first, keyless last — same idea as OpenClaw auto-detect. */\nexport function defaultSearchOrder(ids: readonly string[], keyed: (id: string) => boolean): string[] {\n return [...ids.filter(keyed), ...ids.filter(id => !keyed(id))]\n}\n\nexport function migrateSearchOrder(settings: { searchOrder?: string[]; searchProvider?: string }): string[] {\n return settings.searchOrder ?? (settings.searchProvider ? [settings.searchProvider] : [...DEFAULT_SEARCH_ORDER])\n}\n\nexport function resolveSearchOrder(\n knownIds: readonly string[],\n settings: Pick<WebSettings, 'searchOrder' | 'searchProvider'>,\n _keyed: (id: string) => boolean,\n): string[] {\n return [...new Set(settings.searchOrder.filter(id => knownIds.includes(id)))]\n}\n\nexport function pickActiveSearch(order: readonly string[], configured: (id: string) => boolean): string {\n return order.find(configured) ?? ''\n}\nexport interface ProviderView extends ProviderDescriptor {\n kind: ProviderKind\n configured: boolean\n baseURL?: string\n calls: number\n failures: number\n}\nexport interface WebStatus {\n settings: WebSettings\n providers: ProviderView[]\n searchActive: boolean\n fetchActive: boolean\n storageFailed: boolean\n}\nexport function providerKey(kind: ProviderKind, id: string): string { return `${kind}:${id}` }\nexport function validateBaseURL(value: string): string {\n const url = new URL(value)\n if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash) {\n throw new Error('供应商地址必须是 HTTPS,且不能包含用户名、密码、查询参数或片段。')\n }\n return url.href.replace(/\\/+$/, '')\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { Button, Input, SegmentedTabs, StateDot, Switch, Tag } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { officialUiCss } from '@klarkxy/dsh-plugin-kit/official-ui'\nimport { useCallback, useEffect, useId, useLayoutEffect, useRef, useState, useSyncExternalStore } from 'react'\nimport { PROVIDER_PRICING_CHECKED, searchProviderInfo } from './provider-info.ts'\nimport {\n WEB_SEARCH_RPC_CHANNEL, pickActiveSearch, resolveSearchOrder,\n type ProviderView, type RpcResult, type WebSettings, type WebStatus,\n} from './contracts.ts'\n\nexport const name = 'dsh-web-search-manager-client'\nexport const inject = ['slots', 'connection', 'remote', 'remote.credentials', 'locale'] as const\n\ninterface Credentials {\n describe(refs: string[]): Promise<RpcResult<Record<string, { configured: boolean; writable: boolean; source?: string }>>>\n set(ref: string, value: string): Promise<RpcResult<unknown>>\n unset(ref: string): Promise<RpcResult<unknown>>\n}\ninterface Client {\n connection: { rpc: { call(channel: string, endpoint: string, payload: unknown): Promise<unknown> } }\n remote: { credentials: Credentials }\n /** Host UI language. Optional so bare test harnesses fall back to zh. */\n locale?: { getSnapshot(): { active: string }; subscribe(listener: () => void): () => void }\n slots: {\n inject(key: string, callback: () => unknown): () => void\n register(spec: { name: string; key: string }, render: unknown): () => void\n }\n}\n\nfunction unwrap<T>(result: RpcResult<T>): T {\n if (!result.ok) throw new Error(result.error.message)\n return result.value\n}\nfunction editable(settings: WebSettings): Omit<WebSettings, 'revision'> {\n const { revision: _revision, ...rest } = settings\n return rest\n}\n\nexport function isProviderOn(status: WebStatus, provider: ProviderView): boolean {\n const enabled = provider.kind === 'search' ? status.searchActive : status.fetchActive\n const selected = status.settings[provider.kind === 'search' ? 'searchProvider' : 'fetchProvider']\n return enabled && selected === provider.id\n}\n\nexport function searchBackends(status: WebStatus): ProviderView[] {\n const all = status.providers.filter(provider => provider.kind === 'search')\n const order = resolveSearchOrder(\n all.map(provider => provider.id),\n status.settings,\n id => Boolean(all.find(provider => provider.id === id)?.credentialRef),\n )\n return order.flatMap(id => all.find(provider => provider.id === id) ?? [])\n}\n\nexport function catalogSearchBackends(status: WebStatus): ProviderView[] {\n const enabled = searchBackends(status)\n const rest = status.providers.filter(provider => provider.kind === 'search' && !enabled.some(row => row.id === provider.id))\n return [...enabled, ...rest]\n}\n\nexport function selectedSearchBackend(status: WebStatus): ProviderView | undefined {\n const backends = searchBackends(status)\n const id = pickActiveSearch(backends.map(provider => provider.id), id => Boolean(backends.find(provider => provider.id === id)?.configured))\n return backends.find(provider => provider.id === id)\n}\n\nfunction ExternalLink({ url, label, children }: { url: string; label: string; children: string }) {\n return <a href={url} target=\"_blank\" rel=\"noreferrer noopener\" aria-label={label}\n onClick={event => {\n const bridge = (globalThis as { dshWindow?: { openExternal?(url: string): void } }).dshWindow\n if (bridge?.openExternal) {\n event.preventDefault()\n bridge.openExternal(url)\n }\n }}>{children}</a>\n}\n\nexport function canEnableSearch(\n order: readonly string[],\n providers: readonly ProviderView[],\n keys: Record<string, string>,\n writable: Record<string, boolean>,\n): boolean {\n return order.some(id => {\n const provider = providers.find(item => item.kind === 'search' && item.id === id)\n if (!provider) return false\n if (provider.configured) return true\n const typed = (keys[provider.id] ?? '').trim()\n return Boolean(provider.credentialRef && typed && writable[provider.credentialRef] !== false)\n })\n}\n\nexport function nextSearchEnabled(\n currentlyEnabled: boolean,\n nextOrder: readonly string[],\n providers: readonly ProviderView[],\n keys: Record<string, string>,\n writable: Record<string, boolean>,\n): boolean {\n return currentlyEnabled && canEnableSearch(nextOrder, providers, keys, writable)\n}\n\nfunction ConfirmButton(props: { label: string; confirmLabel: string; disabled?: boolean; onConfirm(): void }) {\n const [armed, setArmed] = useState(false)\n const timer = useRef<ReturnType<typeof setTimeout>>(undefined)\n useEffect(() => () => clearTimeout(timer.current), [])\n function disarm() {\n clearTimeout(timer.current)\n setArmed(false)\n }\n return <Button variant=\"outline\" size=\"sm\" className=\"ws-danger\" disabled={props.disabled} data-armed={armed || undefined}\n onClick={() => {\n if (!armed) {\n setArmed(true)\n timer.current = setTimeout(() => setArmed(false), 3000)\n return\n }\n disarm()\n props.onConfirm()\n }}\n onBlur={disarm}>{armed ? props.confirmLabel : props.label}</Button>\n}\n\nconst copy = {\n zh: {\n tabsLabel: '网络搜索设置', tabProviders: '搜索服务', tabLimits: '请求限制',\n loading: '正在读取设置…', loadFailed: '读取设置失败:', reconnect: '重新连接',\n failed: '操作失败。', readOnly: '凭据只读,无法保存。',\n keyDeleted: '已删除 Key。', keySaved: '已保存 Key。', saved: '已保存。',\n storageFailed: '保存失败,重新保存前网络访问已暂停。',\n empty: '暂无可用搜索后端,请启用一个供应商。', toolTitle: '联网搜索', needBackend: '需选择搜索服务并配置 Key。',\n backends: '搜索后端', dragPrefix: '拖动排序 ', dragHint: '拖动排序,或用上下方向键',\n inUse: '当前使用', signup: '去注册', pricing: '费用说明', website: '官网',\n needsKey: '待配置 Key', unavailable: '暂不可用', sharedKey: '与其他设置共用凭据',\n keyConfigured: '已配置,留空不替换', keyPlaceholder: '输入 API Key',\n saveKey: '保存 Key', deleteKey: '删除 Key', confirmDelete: '确认删除 Key?',\n test: '测试连接(可能计费)', unsaved: '有未保存的修改', save: '保存',\n saveHint: '开关与排序立即生效;Key 与限制需保存。',\n maxResults: '每条查询结果上限', maxQueries: '每次调用查询上限',\n timeoutMs: '请求超时(毫秒)', maxFetchChars: '正文字符上限',\n },\n en: {\n tabsLabel: 'Web search settings', tabProviders: 'Search services', tabLimits: 'Request limits',\n loading: 'Loading settings…', loadFailed: 'Could not load settings: ', reconnect: 'Reconnect',\n failed: 'Operation failed.', readOnly: 'Read-only credential; cannot save.',\n keyDeleted: 'Key deleted.', keySaved: 'Key saved.', saved: 'Saved.',\n storageFailed: 'Save failed; network access is paused until you save again.',\n empty: 'No search backends yet; enable a provider.', toolTitle: 'Web search', needBackend: 'Needs a search service with a key.',\n backends: 'Search backends', dragPrefix: 'Reorder ', dragHint: 'Drag to reorder, or use arrow keys',\n inUse: 'In use', signup: 'Sign up', pricing: 'Pricing', website: 'Website',\n needsKey: 'Key required', unavailable: 'Unavailable', sharedKey: 'Shares a credential with other settings',\n keyConfigured: 'Configured; empty keeps it', keyPlaceholder: 'Enter API key',\n saveKey: 'Save key', deleteKey: 'Delete key', confirmDelete: 'Delete this key?',\n test: 'Test connection (may be billed)', unsaved: 'Unsaved changes', save: 'Save',\n saveHint: 'Switches and order apply now; keys and limits need saving.',\n maxResults: 'Max results/query', maxQueries: 'Max queries/call',\n timeoutMs: 'Request timeout (ms)', maxFetchChars: 'Max text chars',\n },\n} as const\n\ntype Copy = (typeof copy)['zh'] | (typeof copy)['en']\n\nfunction movedText(locale: 'zh' | 'en', label: string, position: number): string {\n return locale === 'zh' ? `${label} 已移至第 ${position} 位` : `${label} moved to position ${position}`\n}\nfunction pricingCheckedText(locale: 'zh' | 'en', date: string): string {\n return locale === 'zh' ? `价格核对于 ${date},额度与费用以供应商账户为准。` : `Prices checked on ${date}; your provider account is authoritative.`\n}\nfunction testOkText(locale: 'zh' | 'en', sources: number): string {\n return locale === 'zh' ? `连接正常,返回 ${sources} 条来源。` : `Connection OK: ${sources} sources returned.`\n}\nfunction limitInvalidText(locale: 'zh' | 'en', label: string, min: number, max: number): string {\n return locale === 'zh' ? `${label}需为 ${min}–${max} 之间的整数。` : `${label} must be a whole number from ${min} to ${max}.`\n}\n\nconst LIMITS = [\n ['maxResults', 1, 20],\n ['maxQueries', 1, 5],\n ['timeoutMs', 1000, 120000],\n ['maxFetchChars', 1000, 200000],\n] as const\ntype LimitKey = (typeof LIMITS)[number][0]\n\n/** A limit field's raw text, or `undefined` when it is not a whole number in range. */\nexport function parseLimit(raw: string, min: number, max: number): number | undefined {\n const text = raw.trim()\n if (!/^\\d+$/u.test(text)) return undefined\n const value = Number(text)\n return value >= min && value <= max ? value : undefined\n}\n\n/**\n * Settings written by an immediate action (a switch or a reorder). It keeps the\n * saved limits and never includes typed-but-unsaved keys or limit drafts.\n */\nexport function immediateUpdate(settings: WebSettings, on: boolean, order: string[]): Omit<WebSettings, 'revision'> {\n return { ...editable(settings), searchOrder: order, searchEnabled: on, fetchProvider: 'http', fetchEnabled: on }\n}\n\nfunction limitTexts(settings: WebSettings): Record<LimitKey, string> {\n return {\n maxResults: String(settings.maxResults), maxQueries: String(settings.maxQueries),\n timeoutMs: String(settings.timeoutMs), maxFetchChars: String(settings.maxFetchChars),\n }\n}\n\nfunction useHostLocale(client: Client): 'zh' | 'en' {\n const subscribe = useCallback((listener: () => void) => client.locale?.subscribe(listener) ?? (() => {}), [client])\n const snapshot = useCallback(() => client.locale?.getSnapshot().active ?? 'zh', [client])\n return String(useSyncExternalStore(subscribe, snapshot, snapshot)).startsWith('zh') ? 'zh' : 'en'\n}\n\n/** Keyboard reorders are batched: persist once the arrows stop for this long. */\nconst REORDER_DEBOUNCE_MS = 500\n\nexport function NetworkSearchSettings({ client }: { client: Client }) {\n const locale = useHostLocale(client)\n const text: Copy = copy[locale]\n const tabsId = useId()\n const [tab, setTab] = useState<'providers' | 'limits'>('providers')\n const [status, setStatus] = useState<WebStatus>()\n const [limitDraft, setLimitDraft] = useState<Record<LimitKey, string>>()\n const [invalid, setInvalid] = useState<Partial<Record<LimitKey, boolean>>>({})\n const [keys, setKeys] = useState<Record<string, string>>({})\n const [busy, setBusy] = useState(false)\n const [pendingOrder, setPendingOrder] = useState<string[] | null>(null)\n const [dragSource, setDragSource] = useState<string | null>(null)\n const [dropTarget, setDropTarget] = useState<string | null>(null)\n const [sortAnnouncement, setSortAnnouncement] = useState('')\n const [note, setNote] = useState('')\n const [error, setError] = useState('')\n const [loadError, setLoadError] = useState('')\n const [writable, setWritable] = useState<Record<string, boolean>>({})\n const statusRef = useRef(status)\n statusRef.current = status\n const pendingRef = useRef<string[] | null>(null)\n const timerRef = useRef<ReturnType<typeof setTimeout>>(undefined)\n const handleRefs = useRef(new Map<string, HTMLButtonElement>())\n const refocusRef = useRef<string | null>(null)\n\n async function call<T>(endpoint: string, payload: unknown = {}): Promise<T> {\n return unwrap(await client.connection.rpc.call(WEB_SEARCH_RPC_CHANNEL, endpoint, payload) as RpcResult<T>)\n }\n function adopt(next: WebStatus, resetDraft = false) {\n const previous = statusRef.current\n statusRef.current = next\n setStatus(next)\n setLimitDraft(current => {\n const incoming = limitTexts(next.settings)\n if (!current || !previous || resetDraft) return incoming\n const baseline = limitTexts(previous.settings)\n return Object.fromEntries(LIMITS.map(([key]) =>\n [key, current[key] === baseline[key] ? incoming[key] : current[key]],\n )) as Record<LimitKey, string>\n })\n if (resetDraft) setInvalid({})\n }\n async function load(resetDraft = false) {\n const next = await call<WebStatus>('status')\n adopt(next, resetDraft)\n setLoadError('')\n const refs = next.providers.flatMap(provider => provider.credentialRef ? [provider.credentialRef] : [])\n if (refs.length) {\n const credentials = unwrap(await client.remote.credentials.describe(refs))\n setWritable(Object.fromEntries(Object.entries(credentials).map(([ref, value]) => [ref, value.writable])))\n }\n return next\n }\n useEffect(() => {\n void load().catch(cause => setLoadError(cause instanceof Error && cause.message ? cause.message : text.failed))\n }, [client])\n\n // A reorder still waiting for its debounce is written on unmount, not dropped.\n useEffect(() => () => {\n if (timerRef.current === undefined) return\n clearTimeout(timerRef.current)\n const current = statusRef.current\n const next = pendingRef.current\n if (current && next) {\n void call('update', { settings: immediateUpdate(current.settings, current.settings.searchEnabled, next), expectedRevision: current.settings.revision }).catch(() => {})\n }\n }, [])\n\n // Keep keyboard focus on the handle that was just moved.\n useLayoutEffect(() => {\n const id = refocusRef.current\n if (!id) return\n refocusRef.current = null\n const handle = handleRefs.current.get(id)\n if (handle && document.activeElement !== handle) handle.focus()\n })\n\n async function action(run: () => Promise<void>) {\n setBusy(true); setNote(''); setError('')\n try { await run() }\n catch (cause) { setError(cause instanceof Error && cause.message ? cause.message : text.failed); await load().catch(() => {}) }\n finally { setBusy(false) }\n }\n\n /** Switches and reorders: settings only, applied at once. */\n function runImmediate(on: boolean, order: string[]) {\n clearTimeout(timerRef.current); timerRef.current = undefined\n pendingRef.current = null\n void action(async () => {\n const current = statusRef.current\n if (!current) return\n const next = await call<WebStatus>('update', { settings: immediateUpdate(current.settings, on, order), expectedRevision: current.settings.revision })\n setStatus(next)\n await load()\n }).then(() => { if (pendingRef.current === null) setPendingOrder(null) })\n }\n\n /** Writes every typed key. Explicit actions only (Save, Save key, Test). */\n async function saveKeys(only?: ProviderView) {\n if (!status) return\n for (const provider of status.providers) {\n if (provider.kind !== 'search' || (only && provider.id !== only.id)) continue\n const snapshot = keys[provider.id] ?? ''\n const typed = snapshot.trim()\n if (!provider.credentialRef || !typed) continue\n if (writable[provider.credentialRef] === false) throw new Error(text.readOnly)\n unwrap(await client.remote.credentials.set(provider.credentialRef, typed))\n setKeys(current => current[provider.id] === snapshot ? { ...current, [provider.id]: '' } : current)\n }\n }\n\n async function removeKey(provider: ProviderView) {\n if (!provider.credentialRef || provider.credentialShared || !status) return\n unwrap(await client.remote.credentials.unset(provider.credentialRef))\n setKeys(current => ({ ...current, [provider.id]: '' }))\n await load()\n setNote(text.keyDeleted)\n }\n\n if (!status || !limitDraft) {\n return <section className=\"web-search-settings ws-root dsh-ui-panel\">\n {loadError\n ? <p role=\"alert\" className=\"dsh-ui-error\">{text.loadFailed}{loadError}</p>\n : <p role=\"status\" className=\"dsh-ui-hint\">{text.loading}</p>}\n {loadError ? <div className=\"dsh-ui-actions\"><Button variant=\"outline\" size=\"sm\" disabled={busy}\n onClick={() => void action(async () => { await load() })}>{text.reconnect}</Button></div> : null}\n </section>\n }\n\n const saved = status\n const savedOrder = searchBackends(saved).map(provider => provider.id)\n const order = pendingOrder ?? savedOrder\n const catalog = catalogSearchBackends(saved)\n const backends = [\n ...order.flatMap(id => catalog.find(provider => provider.id === id) ?? []),\n ...catalog.filter(provider => !order.includes(provider.id)),\n ]\n const selected = selectedSearchBackend(saved)\n const on = saved.settings.searchEnabled\n // Immediate switches never write typed keys, so only saved keys count here.\n const canEnable = canEnableSearch(order, saved.providers, {}, writable)\n const savedLimits = limitTexts(saved.settings)\n const limitsDirty = LIMITS.some(([key]) => limitDraft[key] !== savedLimits[key])\n const keysDirty = Object.values(keys).some(value => value.trim())\n const reordering = pendingOrder !== null\n\n function move(id: string, nextIndex: number, keyboard = false) {\n const index = order.indexOf(id)\n if (busy || index < 0 || nextIndex < 0 || nextIndex >= order.length || index === nextIndex) return\n const next = [...order]\n const [item] = next.splice(index, 1)\n next.splice(nextIndex, 0, item)\n pendingRef.current = next\n setPendingOrder(next)\n if (keyboard) refocusRef.current = id\n setSortAnnouncement(movedText(locale, backends.find(provider => provider.id === id)?.label ?? id, nextIndex + 1))\n clearTimeout(timerRef.current)\n const delay = keyboard ? REORDER_DEBOUNCE_MS : 0\n timerRef.current = setTimeout(() => {\n timerRef.current = undefined\n const batched = pendingRef.current\n const current = statusRef.current\n if (batched && current) runImmediate(current.settings.searchEnabled, batched)\n }, delay)\n }\n\n function endDrag() {\n setDragSource(null)\n setDropTarget(null)\n }\n\n function saveAll() {\n const parsed: Partial<Record<LimitKey, number>> = {}\n const nextInvalid: Partial<Record<LimitKey, boolean>> = {}\n const messages: string[] = []\n for (const [key, min, max] of LIMITS) {\n const value = parseLimit(limitDraft![key], min, max)\n if (value === undefined) { nextInvalid[key] = true; messages.push(limitInvalidText(locale, text[key], min, max)) }\n else parsed[key] = value\n }\n setInvalid(nextInvalid)\n if (messages.length) { setNote(''); setError(messages.join(' ')); return }\n void action(async () => {\n await saveKeys()\n const current = statusRef.current!\n const next = await call<WebStatus>('update', {\n settings: { ...editable(current.settings), ...parsed, fetchProvider: 'http', fetchEnabled: current.settings.searchEnabled },\n expectedRevision: current.settings.revision,\n })\n adopt(next, true)\n await load()\n setNote(text.saved)\n })\n }\n\n return <section className=\"web-search-settings ws-root dsh-ui-panel\" data-testid=\"web-search-settings\">\n <SegmentedTabs<'providers' | 'limits'>\n value={tab}\n onChange={setTab}\n label={text.tabsLabel}\n items={[\n { value: 'providers', label: text.tabProviders, id: tabsId + '-providers-tab', panelId: tabsId + '-providers-panel' },\n { value: 'limits', label: text.tabLimits, id: tabsId + '-limits-tab', panelId: tabsId + '-limits-panel' },\n ]}\n />\n <span className=\"ws-sr-only\" role=\"status\" aria-live=\"polite\">{sortAnnouncement}</span>\n {error && <p role=\"alert\" className=\"dsh-ui-error\">{error}</p>}\n {note && <p role=\"status\" className=\"dsh-ui-notice\">{note}</p>}\n {saved.storageFailed && <p role=\"alert\" className=\"dsh-ui-banner dsh-ui-banner--danger\">{text.storageFailed}</p>}\n <div role=\"tabpanel\" id={tabsId + '-providers-panel'} aria-labelledby={tabsId + '-providers-tab'}\n hidden={tab !== 'providers'} tabIndex={0}>\n {backends.length === 0 ? <p className=\"dsh-ui-empty\">{text.empty}</p> : <article\n className=\"web-search-card dsh-ui-card dsh-ui-card--flat\"\n data-testid=\"web-search-tool\"\n data-on={on ? 'true' : 'false'}>\n <header className=\"ws-card-head\">\n <div>\n <h3 className=\"dsh-ui-title\">{text.toolTitle}</h3>\n {!canEnable && <p className=\"dsh-ui-hint\">{text.needBackend}</p>}\n </div>\n <Switch\n checked={on}\n label={text.toolTitle}\n disabled={busy || (!on && !canEnable)}\n onChange={next => runImmediate(next, order)}\n />\n </header>\n <ol className=\"web-search-rank\" aria-label={text.backends}>\n {backends.map(provider => {\n const participating = order.includes(provider.id)\n const rank = order.indexOf(provider.id)\n const active = saved.searchActive && selected?.id === provider.id\n const info = searchProviderInfo(provider)\n const needsKey = Boolean(provider.credentialRef)\n const shared = Boolean(provider.credentialShared)\n const showKey = needsKey && participating && (!shared || !provider.configured)\n const canSort = participating && order.length > 1\n const readOnly = writable[provider.credentialRef ?? ''] === false\n const typedKey = (keys[provider.id] ?? '').trim()\n return <li key={provider.id} className={active ? 'is-active' : undefined} data-testid={`web-search-rank-${provider.id}`}\n data-dragging={dragSource === provider.id || undefined}\n data-drop={dropTarget === provider.id && dragSource ? (order.indexOf(dragSource) < rank ? 'after' : 'before') : undefined}\n onDragOver={event => {\n if (busy || !canSort || !dragSource || dragSource === provider.id) return\n event.preventDefault()\n event.dataTransfer.dropEffect = 'move'\n setDropTarget(provider.id)\n }}\n onDragLeave={event => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setDropTarget(null)\n }}\n onDrop={event => {\n if (busy || !canSort || !dragSource) return\n event.preventDefault()\n move(dragSource, rank)\n endDrag()\n }}>\n {canSort ? <Button variant=\"ghost\" size=\"sm\" className=\"web-search-drag-handle\"\n ref={(element: HTMLButtonElement | null) => {\n if (element) handleRefs.current.set(provider.id, element)\n else handleRefs.current.delete(provider.id)\n }}\n icon={<svg width=\"16\" height=\"20\" viewBox=\"0 0 16 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <circle cx=\"5\" cy=\"5\" r=\"1.5\" /><circle cx=\"11\" cy=\"5\" r=\"1.5\" />\n <circle cx=\"5\" cy=\"10\" r=\"1.5\" /><circle cx=\"11\" cy=\"10\" r=\"1.5\" />\n <circle cx=\"5\" cy=\"15\" r=\"1.5\" /><circle cx=\"11\" cy=\"15\" r=\"1.5\" />\n </svg>}\n draggable={!busy} aria-disabled={busy}\n aria-label={text.dragPrefix + provider.label}\n title={text.dragHint}\n onDragStart={event => {\n if (busy) { event.preventDefault(); return }\n event.dataTransfer.effectAllowed = 'move'\n event.dataTransfer.setData('application/x-dsh-search-provider', provider.id)\n const row = event.currentTarget.closest('li')\n if (row) event.dataTransfer.setDragImage(row, 16, 16)\n setDragSource(provider.id)\n setSortAnnouncement('')\n }}\n onDragEnd={endDrag}\n onKeyDown={event => {\n if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return\n event.preventDefault()\n move(provider.id, rank + (event.key === 'ArrowUp' ? -1 : 1), true)\n }} /> : <span className=\"web-search-rank-index\">{participating ? rank + 1 : '—'}</span>}\n <div className=\"web-search-provider\">\n <div className=\"web-search-provider-heading\">\n <strong className=\"dsh-ui-heading\">{provider.label}</strong>\n {active && <Tag tone=\"success\">{text.inUse}</Tag>}\n {provider.signupUrl && <ExternalLink url={provider.signupUrl} label={provider.label + ' ' + text.signup}>{text.signup}</ExternalLink>}\n </div>\n <div className=\"web-search-provider-info\">\n <p>{info.description}</p>\n {/* Pricing stays visible even when a provider is off, so users can compare before enabling. */}\n <p>{info.pricing}{info.pricingUrl && <> <ExternalLink url={info.pricingUrl}\n label={provider.label + ' ' + text.pricing}>{provider.id === 'ddg' ? text.website : text.pricing}</ExternalLink></>}</p>\n </div>\n {participating && !provider.configured ? <p className=\"ws-provider-note\">\n <StateDot state=\"warning\" />\n <span>{needsKey ? text.needsKey : text.unavailable}</span>\n </p> : null}\n {shared && participating && <small className=\"dsh-ui-meta\">{provider.credentialHint ?? text.sharedKey}</small>}\n {showKey ? <label className=\"dsh-ui-field\">\n <span className=\"dsh-ui-label\">API Key</span>\n <Input className=\"ws-input\" type=\"password\" autoComplete=\"off\" spellCheck={false}\n disabled={busy || readOnly}\n value={keys[provider.id] ?? ''}\n placeholder={provider.configured ? text.keyConfigured : text.keyPlaceholder}\n onChange={event => setKeys(current => ({ ...current, [provider.id]: event.target.value }))} />\n </label> : null}\n {showKey || (needsKey && !shared && provider.configured) ? <div className=\"dsh-ui-actions\">\n {showKey ? <Button variant=\"outline\" size=\"sm\" disabled={busy || readOnly || !typedKey}\n onClick={() => void action(async () => { await saveKeys(provider); await load(); setNote(text.keySaved) })}>\n {text.saveKey}</Button> : null}\n {needsKey && !shared && provider.configured ? <ConfirmButton\n disabled={busy || readOnly}\n label={text.deleteKey} confirmLabel={text.confirmDelete}\n onConfirm={() => void action(() => removeKey(provider))} /> : null}\n </div> : null}\n </div>\n <div className=\"web-search-rank-move\">\n <Switch\n checked={participating}\n label={provider.label}\n disabled={busy}\n onChange={next => {\n const following = next ? [...order, provider.id] : order.filter(id => id !== provider.id)\n runImmediate(nextSearchEnabled(saved.settings.searchEnabled, following, saved.providers, {}, writable), following)\n }} />\n </div>\n </li>\n })}\n </ol>\n <p className=\"dsh-ui-hint\">{pricingCheckedText(locale, PROVIDER_PRICING_CHECKED)}</p>\n {on ? <div className=\"dsh-ui-actions\">\n <Button variant=\"outline\" size=\"md\" disabled={busy || reordering} onClick={() => void action(async () => {\n // Testing is explicit, so typed keys are saved first and the request uses them.\n await saveKeys()\n const result = await call<{ sources: number }>('test')\n await load()\n setNote(testOkText(locale, result.sources))\n })}>{text.test}</Button>\n </div> : null}\n </article>}\n </div>\n <div role=\"tabpanel\" id={tabsId + '-limits-panel'} aria-labelledby={tabsId + '-limits-tab'}\n hidden={tab !== 'limits'} tabIndex={0}>\n <fieldset className=\"web-search-limits\" disabled={busy || reordering} aria-label={text.tabLimits}>\n {LIMITS.map(([key, min, max]) => (\n <label key={key} className=\"ws-limit\">\n <span className=\"dsh-ui-label\">{text[key]}</span>\n <Input className=\"ws-input\" type=\"number\" min={min} max={max} step={1} value={limitDraft[key]}\n aria-invalid={invalid[key] || undefined}\n onChange={event => {\n const raw = event.target.value\n setLimitDraft(current => current ? { ...current, [key]: raw } : current)\n setInvalid(current => ({ ...current, [key]: false }))\n }}\n onBlur={() => setInvalid(current => ({ ...current, [key]: parseLimit(limitDraft[key], min, max) === undefined }))} />\n {invalid[key] ? <span className=\"dsh-ui-error\">{limitInvalidText(locale, text[key], min, max)}</span> : null}\n </label>\n ))}\n </fieldset>\n </div>\n <div className=\"dsh-ui-actions dsh-ui-actions-end\">\n <span className=\"dsh-ui-meta\">{limitsDirty || keysDirty ? text.unsaved : text.saveHint}</span>\n <Button variant=\"primary\" size=\"md\" disabled={busy || reordering} onClick={saveAll}>{text.save}</Button>\n </div>\n </section>\n}\n\n/* The contract owns the type tiers, the card, the field, the button row, the\n * notice, the focus ring and the state colours. What is left is this panel's own\n * geometry: the reading width, the ranked three-column row, the drag affordance,\n * the drop indicator, the screen-reader-only announcer and the limits grid. */\nconst styles = `${officialUiCss('ws-root')}\n.ws-root { max-width: 760px; }\n.ws-card-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding-bottom: 8px; }\n.ws-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n}\n.ws-provider-note { display: flex; align-items: center; gap: 6px; }\n.web-search-provider { display: grid; gap: 8px; min-width: 0; }\n.web-search-provider-info { display: grid; gap: 3px; font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-secondary); overflow-wrap: anywhere; }\n.web-search-provider-heading { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; min-height: 24px; }\n.web-search-settings a { color: var(--dsw-alias-state-business-primary); font-size: 12px; line-height: 18px; text-underline-offset: 3px; }\n/* The primitive renders a 32px control in an inline-flex wrapper; a settings\n * field needs it to fill the column it sits in. */\n.ws-input { width: 100%; }\n.web-search-rank { margin: 0; padding: 0; list-style: none; }\n.web-search-rank li {\n position: relative;\n display: grid;\n grid-template-columns: 24px minmax(0, 1fr) auto;\n gap: 10px;\n align-items: start;\n padding: 14px 0;\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.web-search-settings button.web-search-drag-handle {\n display: grid;\n place-items: center;\n width: 24px;\n height: 24px;\n min-height: 24px;\n padding: 0;\n cursor: grab;\n opacity: 0.65;\n}\n.web-search-settings button.web-search-drag-handle:hover { opacity: 1; }\n.web-search-settings button.web-search-drag-handle:active { cursor: grabbing; }\n.web-search-settings button.web-search-drag-handle[aria-disabled='true'] { cursor: wait; opacity: 0.4; }\n.web-search-rank li[data-dragging] { opacity: 0.45; }\n.web-search-rank li[data-drop]::after { content: ''; position: absolute; left: 0; right: 0; height: 2px; background: var(--dsw-alias-state-business-primary); pointer-events: none; }\n.web-search-rank li[data-drop='before']::after { top: -1px; }\n.web-search-rank li[data-drop='after']::after { bottom: -1px; }\n.web-search-rank-index { color: var(--dsw-alias-label-tertiary); font-variant-numeric: tabular-nums; line-height: 24px; }\n.web-search-rank-move { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; justify-content: flex-end; padding-top: 2px; }\n.web-search-limits { margin: 0; border: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 20px; }\n/* A two-column grid, so these fields keep the contract's caption and the\n * primitive's control and only own their vertical rhythm — a stacked list is\n * what draws the hairline between fields, and there is nothing to separate. */\n.ws-limit { display: flex; flex-direction: column; gap: 6px; min-width: 0; }\n.ws-danger:hover:not(:disabled),\n.ws-danger[data-armed] { color: var(--dsw-alias-state-error-primary); border-color: var(--dsw-alias-state-error-primary); }\n.ws-danger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover-danger); }\n@media (max-width: 560px) { .web-search-rank-move { flex-direction: column; align-items: flex-end; } .web-search-limits { grid-template-columns: minmax(0, 1fr); } }\n`\n\nexport function apply(ctx: Context): void {\n const client = ctx as unknown as Client\n ctx.effect(() => {\n if (typeof document === 'undefined') return () => {}\n const style = document.createElement('style')\n style.setAttribute('data-plugin', '@klarkxy/dsh-web-search-manager'); style.textContent = styles\n style.dataset.dshWebSearch = ''; document.head.appendChild(style)\n return () => style.remove()\n }, 'web-search-manager.styles')\n ctx.effect(() => client.slots.inject('plugins.bundle.config', () => client.slots.register({\n name: 'plugins.bundle.config', key: '@klarkxy/dsh-web-search-manager',\n }, () => <NetworkSearchSettings client={client} />)), 'web-search-manager.settings')\n}\n"],"mappings":"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"}
|