@klarkxy/dsh-zhihu 0.1.8 → 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.
@@ -18,6 +18,16 @@ type ZhihuRpcResult<T = unknown> = {
18
18
  details: Record<string, unknown>;
19
19
  };
20
20
  };
21
+ declare const ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME = "zhihu_question_recommendations";
22
+ declare const ZHIHU_QUESTION_ANSWERS_TOOL_NAME = "zhihu_question_answers";
23
+ declare const ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME = "zhihu_user_content_detail";
24
+ declare const ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME = "zhihu_user_content_comments";
25
+ declare const ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME = "zhihu_creator_account_stats";
26
+ declare const ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME = "zhihu_creator_content_stats";
27
+ declare const ZHIHU_QUOTA_TOOL_NAME = "zhihu_quota";
28
+ /** Official quota IDs, not local execution counters or predicted balances. */
29
+ declare const ZHIHU_QUOTA_IDS: readonly ["global_search", "zhihu_search", "hot_list", "question_answers", "zhida_openai", "tools", "knowledge", "user_data", "creator"];
30
+ type ZhihuQuotaId = typeof ZHIHU_QUOTA_IDS[number];
21
31
  //#endregion
22
- export { ZHIHU_ASK_TOOL_NAME, ZHIHU_CREDENTIAL_REF, ZHIHU_GLOBAL_SEARCH_TOOL_NAME, ZHIHU_HOT_LIST_TOOL_NAME, ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME, ZHIHU_RPC_CHANNEL, ZHIHU_SEARCH_EVENT, ZHIHU_SEARCH_TOOL_NAME, ZhihuRpcResult };
32
+ export { ZHIHU_ASK_TOOL_NAME, ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME, ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME, ZHIHU_CREDENTIAL_REF, ZHIHU_GLOBAL_SEARCH_TOOL_NAME, ZHIHU_HOT_LIST_TOOL_NAME, ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME, ZHIHU_QUESTION_ANSWERS_TOOL_NAME, ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME, ZHIHU_QUOTA_IDS, ZHIHU_QUOTA_TOOL_NAME, ZHIHU_RPC_CHANNEL, ZHIHU_SEARCH_EVENT, ZHIHU_SEARCH_TOOL_NAME, ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME, ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME, ZhihuQuotaId, ZhihuRpcResult };
23
33
  //# sourceMappingURL=contracts.d.ts.map
package/lib/contracts.js CHANGED
@@ -7,7 +7,26 @@ const ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME = "zhihu_knowledge_search";
7
7
  const ZHIHU_RPC_CHANNEL = "/zhihu";
8
8
  const ZHIHU_CREDENTIAL_REF = "ZHIHU_ACCESS_TOKEN";
9
9
  const ZHIHU_SEARCH_EVENT = "dsh-editor/zhihu-search";
10
+ const ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME = "zhihu_question_recommendations";
11
+ const ZHIHU_QUESTION_ANSWERS_TOOL_NAME = "zhihu_question_answers";
12
+ const ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME = "zhihu_user_content_detail";
13
+ const ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME = "zhihu_user_content_comments";
14
+ const ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME = "zhihu_creator_account_stats";
15
+ const ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME = "zhihu_creator_content_stats";
16
+ const ZHIHU_QUOTA_TOOL_NAME = "zhihu_quota";
17
+ /** Official quota IDs, not local execution counters or predicted balances. */
18
+ const ZHIHU_QUOTA_IDS = [
19
+ "global_search",
20
+ "zhihu_search",
21
+ "hot_list",
22
+ "question_answers",
23
+ "zhida_openai",
24
+ "tools",
25
+ "knowledge",
26
+ "user_data",
27
+ "creator"
28
+ ];
10
29
  //#endregion
11
- export { ZHIHU_ASK_TOOL_NAME, ZHIHU_CREDENTIAL_REF, ZHIHU_GLOBAL_SEARCH_TOOL_NAME, ZHIHU_HOT_LIST_TOOL_NAME, ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME, ZHIHU_RPC_CHANNEL, ZHIHU_SEARCH_EVENT, ZHIHU_SEARCH_TOOL_NAME };
30
+ export { ZHIHU_ASK_TOOL_NAME, ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME, ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME, ZHIHU_CREDENTIAL_REF, ZHIHU_GLOBAL_SEARCH_TOOL_NAME, ZHIHU_HOT_LIST_TOOL_NAME, ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME, ZHIHU_QUESTION_ANSWERS_TOOL_NAME, ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME, ZHIHU_QUOTA_IDS, ZHIHU_QUOTA_TOOL_NAME, ZHIHU_RPC_CHANNEL, ZHIHU_SEARCH_EVENT, ZHIHU_SEARCH_TOOL_NAME, ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME, ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME };
12
31
 
13
32
  //# sourceMappingURL=contracts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.js","names":[],"sources":["../src/contracts.ts"],"sourcesContent":["export const ZHIHU_SEARCH_TOOL_NAME = 'zhihu_search'\nexport const ZHIHU_GLOBAL_SEARCH_TOOL_NAME = 'zhihu_global_search'\nexport const ZHIHU_HOT_LIST_TOOL_NAME = 'zhihu_hot_list'\nexport const ZHIHU_ASK_TOOL_NAME = 'zhihu_ask'\nexport const ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME = 'zhihu_knowledge_search'\nexport const ZHIHU_RPC_CHANNEL = '/zhihu'\nexport const ZHIHU_CREDENTIAL_REF = 'ZHIHU_ACCESS_TOKEN'\nexport const ZHIHU_SEARCH_EVENT = 'dsh-editor/zhihu-search'\nexport type ZhihuRpcResult<T = unknown> = { ok: true; value: T } | { ok: false; error: { code: string; message: string; details: Record<string, unknown> } }\n"],"mappings":";AAAA,MAAa,yBAAyB;AACtC,MAAa,gCAAgC;AAC7C,MAAa,2BAA2B;AACxC,MAAa,sBAAsB;AACnC,MAAa,mCAAmC;AAChD,MAAa,oBAAoB;AACjC,MAAa,uBAAuB;AACpC,MAAa,qBAAqB"}
1
+ {"version":3,"file":"contracts.js","names":[],"sources":["../src/contracts.ts"],"sourcesContent":["export const ZHIHU_SEARCH_TOOL_NAME = 'zhihu_search'\nexport const ZHIHU_GLOBAL_SEARCH_TOOL_NAME = 'zhihu_global_search'\nexport const ZHIHU_HOT_LIST_TOOL_NAME = 'zhihu_hot_list'\nexport const ZHIHU_ASK_TOOL_NAME = 'zhihu_ask'\nexport const ZHIHU_KNOWLEDGE_SEARCH_TOOL_NAME = 'zhihu_knowledge_search'\nexport const ZHIHU_RPC_CHANNEL = '/zhihu'\nexport const ZHIHU_CREDENTIAL_REF = 'ZHIHU_ACCESS_TOKEN'\nexport const ZHIHU_SEARCH_EVENT = 'dsh-editor/zhihu-search'\nexport type ZhihuRpcResult<T = unknown> = { ok: true; value: T } | { ok: false; error: { code: string; message: string; details: Record<string, unknown> } }\n\nexport const ZHIHU_QUESTION_RECOMMENDATIONS_TOOL_NAME = 'zhihu_question_recommendations'\nexport const ZHIHU_QUESTION_ANSWERS_TOOL_NAME = 'zhihu_question_answers'\nexport const ZHIHU_USER_CONTENT_DETAIL_TOOL_NAME = 'zhihu_user_content_detail'\nexport const ZHIHU_USER_CONTENT_COMMENTS_TOOL_NAME = 'zhihu_user_content_comments'\nexport const ZHIHU_CREATOR_ACCOUNT_STATS_TOOL_NAME = 'zhihu_creator_account_stats'\nexport const ZHIHU_CREATOR_CONTENT_STATS_TOOL_NAME = 'zhihu_creator_content_stats'\nexport const ZHIHU_QUOTA_TOOL_NAME = 'zhihu_quota'\n\n/** Official quota IDs, not local execution counters or predicted balances. */\nexport const ZHIHU_QUOTA_IDS = [\n 'global_search', 'zhihu_search', 'hot_list', 'question_answers',\n 'zhida_openai', 'tools', 'knowledge', 'user_data', 'creator',\n] as const\nexport type ZhihuQuotaId = typeof ZHIHU_QUOTA_IDS[number]\n"],"mappings":";AAAA,MAAa,yBAAyB;AACtC,MAAa,gCAAgC;AAC7C,MAAa,2BAA2B;AACxC,MAAa,sBAAsB;AACnC,MAAa,mCAAmC;AAChD,MAAa,oBAAoB;AACjC,MAAa,uBAAuB;AACpC,MAAa,qBAAqB;AAGlC,MAAa,2CAA2C;AACxD,MAAa,mCAAmC;AAChD,MAAa,sCAAsC;AACnD,MAAa,wCAAwC;AACrD,MAAa,wCAAwC;AACrD,MAAa,wCAAwC;AACrD,MAAa,wBAAwB;;AAGrC,MAAa,kBAAkB;CAC7B;CAAiB;CAAgB;CAAY;CAC7C;CAAgB;CAAS;CAAa;CAAa;AACrD"}
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ZhihuRpcResult } from "./contracts.js";
1
+ import { ZhihuQuotaId, ZhihuRpcResult } from "./contracts.js";
2
2
  import { ZhihuUsageRecorder } from "./usage.js";
3
3
  import { Context } from "@deepseek-ai/cordis";
4
4
  //#region src/zhihu-client.d.ts
@@ -10,6 +10,9 @@ type ZhihuSearchFetcher = (input: string, init?: {
10
10
  }) => Promise<{
11
11
  ok: boolean;
12
12
  status: number;
13
+ headers?: {
14
+ get(name: string): string | null;
15
+ };
13
16
  text(): Promise<string>;
14
17
  json(): Promise<unknown>;
15
18
  }>;
@@ -21,6 +24,7 @@ type ZhihuSearchResolveOptions = {
21
24
  type ZhihuSearchExecuted = {
22
25
  ok: boolean;
23
26
  results: number;
27
+ quotaId?: ZhihuQuotaId;
24
28
  };
25
29
  type ZhihuClientOptions = ZhihuSearchResolveOptions & {
26
30
  fetcher?: ZhihuSearchFetcher;
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as reportExecuted, a as executeZhihuGlobalSearch, c as normalizeRecallScopes, g as parseZhihuEnvelope, h as ZhihuSearchError, i as executeZhihuAsk, n as ZHIHU_ASK_MODELS, o as executeZhihuHotList, p as executeZhihuSearch, s as executeZhihuKnowledgeSearch, t as ZHIHU_ASK_DEFAULT_MODEL, v as zhihuFetchJson } from "./operations.js";
1
+ import { S as zhihuFetchJson, _ as executeZhihuSearch, a as ZHIHU_ASK_DEFAULT_MODEL, b as parseZhihuEnvelope, c as executeZhihuAsk, d as executeZhihuKnowledgeSearch, f as normalizeRecallScopes, i as zhihuOpenPlatformResultCount, l as executeZhihuGlobalSearch, n as executeZhihuOpenPlatform, o as ZHIHU_ASK_MODELS, r as resolveZhihuOpenPlatformOperation, t as ZHIHU_OPEN_PLATFORM_APIS, u as executeZhihuHotList, x as reportExecuted, y as ZhihuSearchError } from "./open-platform.js";
2
2
  import { ZHIHU_CREDENTIAL_REF, ZHIHU_RPC_CHANNEL, ZHIHU_SEARCH_EVENT } from "./contracts.js";
3
3
  import { createZhihuUsageRecorder, resolveDays, zhihuUsageDomainSpec } from "./usage.js";
4
4
  import { credentialRef } from "@deepseek-ai/dsh-credentials";
@@ -120,7 +120,12 @@ function endpointFromRpcPath(channel, pathname) {
120
120
  return endpoint;
121
121
  }
122
122
  async function dispatchHostRpc(ctx, channel, handler, req, res) {
123
- const rejection = ctx.connection.requestRejection?.(req);
123
+ if (typeof ctx.connection.requestRejection !== "function") {
124
+ res.writeHead(503);
125
+ res.end("host authorization policy is unavailable");
126
+ return;
127
+ }
128
+ const rejection = ctx.connection.requestRejection(req);
124
129
  if (rejection !== void 0) {
125
130
  res.writeHead(rejection);
126
131
  res.end(rejection === 401 ? "unauthorized" : "forbidden");
@@ -305,12 +310,12 @@ const inject = [
305
310
  "storageDomain",
306
311
  "webServer"
307
312
  ];
308
- const fail = (code, message) => ({
313
+ const fail = (code, message, details = {}) => ({
309
314
  ok: false,
310
315
  error: {
311
316
  code,
312
317
  message,
313
- details: {}
318
+ details
314
319
  }
315
320
  });
316
321
  /** One shared service for direct UI RPC and optional Tool wrappers. */
@@ -350,6 +355,9 @@ function createZhihuService(options, usage, notify = () => {}) {
350
355
  signal
351
356
  };
352
357
  let counted = false;
358
+ const operation = resolveZhihuOpenPlatformOperation(endpoint);
359
+ const quotaId = operation ? ZHIHU_OPEN_PLATFORM_APIS[operation].quotaId : void 0;
360
+ const metering = quotaId ? { quotaId } : {};
353
361
  try {
354
362
  if (endpoint === "usage.summary") {
355
363
  await pendingUsage;
@@ -364,11 +372,16 @@ function createZhihuService(options, usage, notify = () => {}) {
364
372
  "global.search",
365
373
  "ask",
366
374
  "knowledge.search"
367
- ].includes(endpoint) && (!query.trim() || query.length > 4e3)) return fail("bad-request", "请输入不超过 4000 字符的查询");
375
+ ].includes(endpoint) && (!query.trim() || query.length > 4e3)) return fail("bad-request", "查询不超过 4000 字符");
368
376
  let value;
369
377
  let results = 0;
370
378
  counted = true;
371
- if (endpoint === "search") {
379
+ if (operation) {
380
+ counted = operation !== "quota";
381
+ const result = await executeZhihuOpenPlatform(operation, payload === void 0 ? {} : payload, client);
382
+ value = result;
383
+ results = zhihuOpenPlatformResultCount(result);
384
+ } else if (endpoint === "search") {
372
385
  const result = await executeZhihuSearch(query, typeof body.count === "number" ? body.count : 5, client);
373
386
  value = result;
374
387
  results = result.items.length;
@@ -406,9 +419,10 @@ function createZhihuService(options, usage, notify = () => {}) {
406
419
  counted = false;
407
420
  return fail("bad-request", `unknown endpoint ${endpoint}`);
408
421
  }
409
- record({
422
+ if (counted) record({
410
423
  ok: true,
411
- results
424
+ results,
425
+ ...metering
412
426
  });
413
427
  return {
414
428
  ok: true,
@@ -417,11 +431,21 @@ function createZhihuService(options, usage, notify = () => {}) {
417
431
  } catch (error) {
418
432
  if (counted) record({
419
433
  ok: false,
420
- results: 0
434
+ results: 0,
435
+ ...metering
421
436
  });
422
437
  if (signal.aborted) return fail("cancelled", "请求已取消");
423
438
  const code = error instanceof ZhihuSearchError ? error.code.toLowerCase().replaceAll("_", "-") : "internal";
424
- return fail(code, error instanceof Error ? error.message : "知乎请求失败");
439
+ const details = {};
440
+ if (error instanceof ZhihuSearchError) {
441
+ for (const key of [
442
+ "status",
443
+ "upstreamCode",
444
+ "retryAfter",
445
+ "retryable"
446
+ ]) if (error[key] !== void 0) details[key] = error[key];
447
+ }
448
+ return fail(code, error instanceof Error ? error.message : "知乎请求失败", details);
425
449
  }
426
450
  }
427
451
  };
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/zhihu-knowledge.ts","../src/host-rpc.ts","../src/web-search-provider.ts","../src/index.ts"],"sourcesContent":["/**\n * 知乎知识库的管理侧能力:列知识库、上传文件。仅供设置页 RPC 使用,\n * 不暴露为模型工具——上传会把文件送入知乎云端,必须是用户在界面上显式发起。\n *\n * 端点(来源:github.com/klarkxy/zhihu-search,src/zhihu_search/upstream/http_client.py):\n * - 列表:GET /api/v1/knowledge/bases?Scope=all|created|subscribed\n * - 上传:POST /api/v1/knowledge/files(multipart: File + 可选 KnowledgeBaseID),同步解析\n */\nimport {\n parseZhihuEnvelope,\n zhihuFetchJson,\n ZhihuSearchError,\n type ZhihuClientOptions,\n} from './zhihu-client.ts'\n\nexport const ZHIHU_KNOWLEDGE_LIST_VERSION = 1\nexport const ZHIHU_KNOWLEDGE_UPLOAD_VERSION = 1\n/** 设置页 RPC 走 JSON/base64 传输,限额压到 20MB(平台上限 100MB)。 */\nexport const ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES = 20 * 1024 * 1024\nexport const ZHIHU_KNOWLEDGE_UPLOAD_TIMEOUT_MS = 180_000\n\nconst KNOWLEDGE_BASES_PATH = '/api/v1/knowledge/bases'\nconst KNOWLEDGE_FILES_PATH = '/api/v1/knowledge/files'\n\nexport const ZHIHU_KNOWLEDGE_FILE_EXTENSIONS = [\n '.pdf', '.md', '.txt', '.ppt', '.pptx', '.xlsx', '.xls', '.docx', '.doc',\n '.webp', '.png', '.jpg', '.mobi', '.epub', '.csv', '.azw3',\n] as const\n\nconst KNOWLEDGE_CONTENT_TYPES: Record<string, string> = {\n '.pdf': 'application/pdf',\n '.md': 'text/markdown',\n '.txt': 'text/plain',\n '.ppt': 'application/vnd.ms-powerpoint',\n '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n '.xls': 'application/vnd.ms-excel',\n '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n '.doc': 'application/msword',\n '.webp': 'image/webp',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.mobi': 'application/x-mobipocket-ebook',\n '.epub': 'application/epub+zip',\n '.csv': 'text/csv',\n '.azw3': 'application/vnd.amazon.ebook',\n}\n\nexport type ZhihuKnowledgeBase = {\n id: string\n name: string\n relation: string\n visibility: string\n isDefault: boolean\n contentCount: number\n}\n\nexport type ZhihuKnowledgeBaseList = {\n version: typeof ZHIHU_KNOWLEDGE_LIST_VERSION\n bases: ZhihuKnowledgeBase[]\n}\n\nfunction normalizeBase(raw: Record<string, unknown>): ZhihuKnowledgeBase {\n return {\n id: typeof raw.KnowledgeBaseID === 'string' ? raw.KnowledgeBaseID : '',\n name: typeof raw.Name === 'string' && raw.Name.length > 0 ? raw.Name : '(未命名知识库)',\n relation: typeof raw.Relation === 'string' ? raw.Relation : '',\n visibility: typeof raw.Visibility === 'string' ? raw.Visibility : '',\n isDefault: raw.IsDefault === true,\n contentCount: typeof raw.ContentCount === 'number' ? raw.ContentCount : 0,\n }\n}\n\nexport async function listZhihuKnowledgeBases(options: ZhihuClientOptions = {}): Promise<ZhihuKnowledgeBaseList> {\n const body = await zhihuFetchJson(KNOWLEDGE_BASES_PATH, {\n params: { Scope: 'all' },\n }, '知乎知识库列表', options)\n const data = parseZhihuEnvelope(body) as { Items?: unknown }\n const items = Array.isArray(data.Items) ? data.Items : []\n return {\n version: ZHIHU_KNOWLEDGE_LIST_VERSION,\n bases: items\n .filter((item): item is Record<string, unknown> => !!item && typeof item === 'object' && !Array.isArray(item))\n .map(normalizeBase)\n .filter((base) => base.id.length > 0),\n }\n}\n\nexport type ZhihuKnowledgeUploadInput = {\n fileName: string\n data: Uint8Array\n /** 指定目标知识库;缺省进默认库。 */\n knowledgeBaseId?: string\n}\n\nexport type ZhihuKnowledgeUpload = {\n version: typeof ZHIHU_KNOWLEDGE_UPLOAD_VERSION\n knowledgeBaseId: string\n recallContentId: string\n fileName: string\n fileSize: number\n title: string\n abstract: string\n originUrl: string\n}\n\n/** 校验文件名与大小,返回小写扩展名。 */\nexport function checkKnowledgeFile(fileName: string, size: number): string {\n const cleaned = fileName.trim()\n if (!cleaned) throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件名不能为空。')\n // 去掉路径成分,只保留文件名\n const base = cleaned.split(/[\\\\/]/).pop() ?? cleaned\n for (const ch of base) {\n const code = ch.codePointAt(0) ?? 0\n if (code < 32 || code === 127) throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件名不能包含控制字符。')\n }\n if (new TextEncoder().encode(base).length > 255) {\n throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件名不能超过 255 个 UTF-8 字节。')\n }\n if (size <= 0) throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件内容不能为空。')\n if (size > ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES) {\n throw new ZhihuSearchError('BAD_RESPONSE', `知识库文件大小不能超过 ${ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES / 1024 / 1024}MB。`)\n }\n const dot = base.lastIndexOf('.')\n const ext = dot >= 0 ? base.slice(dot).toLowerCase() : ''\n if (!(ZHIHU_KNOWLEDGE_FILE_EXTENSIONS as readonly string[]).includes(ext)) {\n throw new ZhihuSearchError('BAD_RESPONSE', `知识库上传仅支持 ${ZHIHU_KNOWLEDGE_FILE_EXTENSIONS.join('、')}。`)\n }\n return ext\n}\n\nexport async function uploadZhihuKnowledgeFile(\n input: ZhihuKnowledgeUploadInput,\n options: ZhihuClientOptions = {},\n): Promise<ZhihuKnowledgeUpload> {\n const cleaned = (input.fileName.trim().split(/[\\\\/]/).pop() ?? input.fileName.trim())\n const ext = checkKnowledgeFile(input.fileName, input.data.byteLength)\n const form = new FormData()\n if (input.knowledgeBaseId) form.set('KnowledgeBaseID', input.knowledgeBaseId)\n form.set('File', new Blob([input.data.buffer as ArrayBuffer], { type: KNOWLEDGE_CONTENT_TYPES[ext] ?? 'application/octet-stream' }), cleaned)\n const body = await zhihuFetchJson(KNOWLEDGE_FILES_PATH, {\n formData: form,\n }, '知乎知识库上传', { ...options, timeoutMs: options.timeoutMs ?? ZHIHU_KNOWLEDGE_UPLOAD_TIMEOUT_MS })\n const data = parseZhihuEnvelope(body) as Record<string, unknown>\n return {\n version: ZHIHU_KNOWLEDGE_UPLOAD_VERSION,\n knowledgeBaseId: typeof data.KnowledgeBaseID === 'string' ? data.KnowledgeBaseID : '',\n recallContentId: typeof data.RecallContentID === 'string' ? data.RecallContentID : '',\n fileName: typeof data.FileName === 'string' ? data.FileName : cleaned,\n fileSize: typeof data.FileSize === 'number' ? data.FileSize : input.data.byteLength,\n title: typeof data.Title === 'string' ? data.Title : '',\n abstract: typeof data.Abstract === 'string' ? data.Abstract : '',\n originUrl: typeof data.OriginUrl === 'string' ? data.OriginUrl : '',\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\n\nconst CHANNEL_PATTERN = /^\\/[A-Za-z0-9._~-]+$/\nconst ENDPOINT_SEGMENT = /^[A-Za-z0-9_$.-]+$/\nconst MAX_BODY_BYTES = 64 * 1024 * 1024\n\nexport type HostRpcHandler = (endpoint: string, payload: unknown, signal: AbortSignal) => Promise<unknown>\n\nexport type HostRpcContext = {\n webServer: {\n register: (route: {\n kind: 'prefix'\n path: string\n handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>\n }) => () => void\n }\n connection: {\n requestRejection?: (request: IncomingMessage) => number | undefined\n }\n}\n\n/** Standalone copy of manuscript Host RPC registration; this package cannot depend on manuscript. */\nexport function registerHostRpc(ctx: HostRpcContext, channel: string, handler: HostRpcHandler): () => void {\n if (!CHANNEL_PATTERN.test(channel) || channel === '/api') {\n throw new Error(`invalid RPC channel ${JSON.stringify(channel)}`)\n }\n return ctx.webServer.register({\n kind: 'prefix',\n path: channel,\n handler: (req, res) => dispatchHostRpc(ctx, channel, handler, req, res),\n })\n}\n\nfunction endpointFromRpcPath(channel: string, pathname: string): string | undefined {\n if (!pathname.startsWith(`${channel}/`)) return undefined\n const endpoint = pathname.slice(channel.length + 1)\n if (endpoint.split('/').some((segment) => segment === '' || segment === '.' || segment === '..' || !ENDPOINT_SEGMENT.test(segment))) {\n return undefined\n }\n return endpoint\n}\n\nasync function dispatchHostRpc(\n ctx: HostRpcContext,\n channel: string,\n handler: HostRpcHandler,\n req: IncomingMessage,\n res: ServerResponse,\n): Promise<void> {\n const rejection = ctx.connection.requestRejection?.(req)\n if (rejection !== undefined) {\n res.writeHead(rejection)\n res.end(rejection === 401 ? 'unauthorized' : 'forbidden')\n return\n }\n const abort = new AbortController()\n res.on('close', () => {\n if (!res.writableEnded) abort.abort()\n })\n const url = new URL(req.url ?? '/', 'http://dsh.internal')\n const endpoint = endpointFromRpcPath(channel, url.pathname)\n if (req.method !== 'POST' || endpoint === undefined) {\n res.writeHead(404)\n res.end('not found')\n return\n }\n const contentType = String(req.headers['content-type'] ?? '').split(';', 1)[0]?.trim().toLowerCase()\n if (contentType !== 'application/json') {\n res.writeHead(415)\n res.end('content type must be application/json')\n return\n }\n const chunks: Buffer[] = []\n let received = 0\n for await (const chunk of req) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n received += buffer.byteLength\n if (received > MAX_BODY_BYTES) {\n res.writeHead(413, { connection: 'close' })\n res.end()\n req.destroy()\n return\n }\n chunks.push(buffer)\n }\n let body: unknown\n try {\n body = JSON.parse(Buffer.concat(chunks).toString('utf8') || 'null')\n } catch {\n res.writeHead(400)\n res.end('body is not JSON')\n return\n }\n const record = body && typeof body === 'object' && !Array.isArray(body) ? body as Record<string, unknown> : {}\n const rpcId = typeof record.rpcId === 'string' ? record.rpcId : 'invalid-request'\n if (record.type !== 'client-request' || record.method !== endpoint) {\n res.writeHead(200, { 'content-type': 'application/json' })\n res.end(JSON.stringify({\n type: 'server-response',\n rpcId,\n result: {\n ok: false,\n error: {\n code: 'gateway/bad-request',\n message: record.method !== endpoint\n ? `method ${JSON.stringify(record.method)} does not match endpoint ${JSON.stringify(endpoint)}`\n : 'invalid client-request message',\n details: { issues: [] },\n },\n },\n }))\n return\n }\n try {\n const result = await handler(endpoint, record.payload, abort.signal)\n res.writeHead(200, { 'content-type': 'application/json' })\n res.end(JSON.stringify({ type: 'server-response', rpcId, result }))\n } catch (error) {\n res.writeHead(500)\n res.end(`handler failure: ${String(error)}`)\n }\n}\n","/**\n * Optional web-search-manager backend. Registers only when this profile already\n * provides `webSearchManager`; Zhihu still works without that plugin.\n * Official model tool remains `web_search`. Dedicated `zhihu_global_search` is unchanged.\n */\nimport { ZHIHU_CREDENTIAL_REF } from './contracts.ts'\nimport { reportExecuted, type ZhihuClientOptions, type ZhihuSearchExecuted } from './zhihu-client.ts'\nimport {\n executeZhihuGlobalSearch,\n ZHIHU_GLOBAL_SEARCH_MAX_COUNT,\n} from './operations.ts'\n\ntype ZhihuWebSearchHost = {\n run<T>(execute: (signal: AbortSignal) => Promise<T>, signal: AbortSignal): Promise<T>\n toolOptions: ZhihuClientOptions & { onExecuted: (event: ZhihuSearchExecuted) => void }\n}\n\nexport const ZHIHU_WEB_SEARCH_ID = 'zhihu-global'\n\nexport const ZHIHU_WEB_SEARCH_DESCRIPTOR = {\n id: ZHIHU_WEB_SEARCH_ID,\n label: '知乎全网搜索',\n description: '融合知乎问答与全网内容,返回可溯源的搜索结果。',\n credentialRef: ZHIHU_CREDENTIAL_REF,\n credentialShared: true,\n credentialHint: '与「知乎资料」共用 Access Secret',\n billing: 'request' as const,\n pricing: '注册可获 5,000 次/天试用额度;超额价格需向平台咨询。',\n pricingUrl: 'https://developer.zhihu.com/',\n signupUrl: 'https://developer.zhihu.com',\n}\n\nexport type ZhihuWebSearchSource = { url: string; title?: string; snippet?: string }\nexport type ZhihuWebSearchResult = { sources: ZhihuWebSearchSource[]; truncated?: boolean }\nexport type ZhihuWebSearchRequest = { query: string; maxResults?: number }\n\nexport type ZhihuWebSearchProvider = {\n readonly id: string\n available(): boolean\n search(request: ZhihuWebSearchRequest, signal?: AbortSignal): Promise<ZhihuWebSearchResult>\n}\n\nexport type ZhihuWebSearchManager = {\n registerSearchProvider(\n descriptor: typeof ZHIHU_WEB_SEARCH_DESCRIPTOR,\n factory: (options: { apiKey?: string; timeoutMs: number }) => ZhihuWebSearchProvider,\n ): () => void\n}\n\nexport type ZhihuWebSearchProviderOptions = ZhihuClientOptions & {\n apiKey?: string\n onExecuted?: (event: ZhihuSearchExecuted) => void\n}\n\nfunction sourceFrom(url: string, title: string, snippet: string): ZhihuWebSearchSource | undefined {\n let parsed: URL\n try { parsed = new URL(url) } catch { return }\n if (!['https:', 'http:'].includes(parsed.protocol) || parsed.username || parsed.password) return\n return {\n url: parsed.href,\n ...(title ? { title: title.slice(0, 1000) } : {}),\n ...(snippet ? { snippet: snippet.slice(0, 8000) } : {}),\n }\n}\n\nfunction isWebSearchManager(value: unknown): value is ZhihuWebSearchManager {\n return !!value && typeof value === 'object' && typeof (value as ZhihuWebSearchManager).registerSearchProvider === 'function'\n}\n\nexport function createZhihuWebSearchProvider(options: ZhihuWebSearchProviderOptions): ZhihuWebSearchProvider {\n const { apiKey, onExecuted, ...client } = options\n return {\n id: ZHIHU_WEB_SEARCH_ID,\n available() { return Boolean(apiKey?.trim()) },\n async search(request, signal) {\n if (!apiKey?.trim()) throw new Error('知乎全网搜索未配置 Access Secret。')\n if (!request.query?.trim() || request.query.length > 4000) throw new Error('查询无效。')\n const count = request.maxResults ?? 5\n if (!Number.isInteger(count) || count < 1 || count > ZHIHU_GLOBAL_SEARCH_MAX_COUNT) {\n throw new Error(`结果数须为 1 至 ${ZHIHU_GLOBAL_SEARCH_MAX_COUNT}。`)\n }\n try {\n signal?.throwIfAborted()\n const result = await executeZhihuGlobalSearch(request.query.trim(), count, 'all', {\n ...client,\n signal,\n env: {},\n resolveCredential: async () => apiKey,\n })\n reportExecuted(onExecuted, { ok: true, results: result.items.length })\n const sources = result.items.flatMap(item => sourceFrom(item.url, item.title, item.summary) ?? [])\n return { sources: sources.slice(0, count), truncated: sources.length > count }\n } catch (error) {\n reportExecuted(onExecuted, { ok: false, results: 0 })\n throw error\n }\n },\n }\n}\n\nexport function registerZhihuGlobalSearchProvider(\n manager: ZhihuWebSearchManager,\n service: ZhihuWebSearchHost,\n): () => void {\n return manager.registerSearchProvider(ZHIHU_WEB_SEARCH_DESCRIPTOR, options => {\n const provider = createZhihuWebSearchProvider({\n ...service.toolOptions,\n apiKey: options.apiKey,\n timeoutMs: options.timeoutMs,\n })\n return {\n id: provider.id,\n available: () => provider.available(),\n search: (request, signal) => service.run(\n combined => provider.search(request, combined),\n signal ?? new AbortController().signal,\n ),\n }\n })\n}\n\n/** Wait for `webSearchManager` if this profile loaded it; no-op otherwise. */\nexport function bindZhihuWebSearch(\n ctx: { inject(deps: readonly string[], apply: (inner: { get(name: string): unknown }) => (() => void) | void): unknown },\n service: ZhihuWebSearchHost,\n): void {\n ctx.inject(['webSearchManager'], (inner) => {\n let manager: unknown\n try { manager = inner.get('webSearchManager') }\n catch { return }\n if (!isWebSearchManager(manager)) return\n return registerZhihuGlobalSearchProvider(manager, service)\n })\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { credentialRef } from '@deepseek-ai/dsh-credentials'\nimport { executeZhihuSearch, ZHIHU_SEARCH_DEFAULT_COUNT } from './search-api.ts'\nimport {\n executeZhihuGlobalSearch, executeZhihuHotList, executeZhihuAsk, executeZhihuKnowledgeSearch,\n normalizeRecallScopes, ZHIHU_ASK_MODELS, ZHIHU_ASK_DEFAULT_MODEL,\n} from './operations.ts'\nimport { listZhihuKnowledgeBases, uploadZhihuKnowledgeFile, ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES } from './zhihu-knowledge.ts'\nimport { type ZhihuClientOptions, type ZhihuSearchExecuted, ZhihuSearchError } from './zhihu-client.ts'\nimport { createZhihuUsageRecorder, resolveDays, zhihuUsageDomainSpec, type ZhihuUsageRecorder } from './usage.ts'\nimport { ZHIHU_RPC_CHANNEL, ZHIHU_CREDENTIAL_REF, ZHIHU_SEARCH_EVENT, type ZhihuRpcResult } from './contracts.ts'\nimport { registerHostRpc, type HostRpcContext } from './host-rpc.ts'\nimport { bindZhihuWebSearch } from './web-search-provider.ts'\n\nexport const name = '@klarkxy/dsh-zhihu'\nexport const inject = ['connection', 'credentials', 'storageDomain', 'webServer'] as const\nexport type ZhihuService = {\n call(endpoint: string, payload: unknown, signal: AbortSignal): Promise<ZhihuRpcResult>\n run<T>(execute: (signal: AbortSignal) => Promise<T>, signal: AbortSignal): Promise<T>\n dispose(): Promise<void>\n usageSummary(days: unknown): Promise<{ days: unknown[] }>\n toolOptions: ZhihuClientOptions & { onExecuted: (event: ZhihuSearchExecuted) => void }\n}\n\ntype Host = Context & HostRpcContext & {\n credentials: { resolve: (ref: ReturnType<typeof credentialRef>) => Promise<{ value: string } | undefined> }\n}\nconst fail = (code: string, message: string): ZhihuRpcResult => ({ ok: false, error: { code, message, details: {} } })\n\n/** One shared service for direct UI RPC and optional Tool wrappers. */\nexport function createZhihuService(options: ZhihuClientOptions, usage: ZhihuUsageRecorder, notify: (event: ZhihuSearchExecuted) => void = () => {}): ZhihuService {\n // Serialize read-modify-write counters; concurrent tools must not lose increments.\n let pendingUsage = Promise.resolve()\n const lifetime = new AbortController()\n const active = new Set<Promise<unknown>>()\n const run: ZhihuService['run'] = (execute, signal) => {\n const combined = AbortSignal.any([signal, lifetime.signal])\n const request = Promise.resolve().then(() => { combined.throwIfAborted(); return execute(combined) })\n active.add(request)\n return request.finally(() => active.delete(request))\n }\n const record = (event: ZhihuSearchExecuted) => {\n pendingUsage = pendingUsage.then(() => usage.record(event)).catch(() => {})\n try { notify(event) } catch { /* observer failure does not change a request */ }\n }\n const service = {\n toolOptions: { ...options, onExecuted: record },\n async usageSummary(days: unknown) { await pendingUsage; return { days: await usage.read(resolveDays(days)) } },\n async call(endpoint: string, payload: unknown, signal: AbortSignal): Promise<ZhihuRpcResult> {\n if (signal.aborted) return fail('cancelled', '请求已取消')\n const body = payload && typeof payload === 'object' && !Array.isArray(payload) ? payload as Record<string, unknown> : {}\n const client = { ...options, signal }\n let counted = false\n try {\n if (endpoint === 'usage.summary') { await pendingUsage; return { ok: true, value: { days: await usage.read(resolveDays(body.days)) } } }\n const query = typeof body.query === 'string' ? body.query : ''\n if (['search', 'global.search', 'ask', 'knowledge.search'].includes(endpoint) && (!query.trim() || query.length > 4000)) {\n return fail('bad-request', '请输入不超过 4000 字符的查询')\n }\n let value: unknown\n let results = 0\n counted = true\n if (endpoint === 'search') {\n const result = await executeZhihuSearch(query, typeof body.count === 'number' ? body.count : ZHIHU_SEARCH_DEFAULT_COUNT, client)\n value = result; results = result.items.length\n } else if (endpoint === 'global.search') {\n const result = await executeZhihuGlobalSearch(query, typeof body.count === 'number' ? body.count : 10,\n body.searchDb === 'realtime' || body.searchDb === 'static' ? body.searchDb : 'all', client)\n value = result; results = result.items.length\n } else if (endpoint === 'hot.list') {\n const result = await executeZhihuHotList(typeof body.limit === 'number' ? body.limit : 10, client)\n value = result; results = result.items.length\n } else if (endpoint === 'ask') {\n const model = (ZHIHU_ASK_MODELS as readonly unknown[]).includes(body.model) ? body.model as typeof ZHIHU_ASK_MODELS[number] : ZHIHU_ASK_DEFAULT_MODEL\n value = await executeZhihuAsk(query, model, client); results = 1\n } else if (endpoint === 'knowledge.search') {\n const result = await executeZhihuKnowledgeSearch(query, typeof body.limit === 'number' ? body.limit : 5, normalizeRecallScopes(body.recallScopes), client)\n value = result; results = result.items.length\n } else if (endpoint === 'knowledge.bases') {\n const result = await listZhihuKnowledgeBases(client); value = result; results = result.bases.length\n } else if (endpoint === 'knowledge.upload') {\n const contentBase64 = typeof body.contentBase64 === 'string' ? body.contentBase64 : ''\n if (!contentBase64) throw new Error('缺少文件内容。')\n if (contentBase64.length > Math.ceil(ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES / 3) * 4 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(contentBase64)) {\n return fail('bad-request', '文件内容无效或超过 20 MB')\n }\n const upload = await uploadZhihuKnowledgeFile({\n fileName: typeof body.fileName === 'string' ? body.fileName : '',\n data: new Uint8Array(Buffer.from(contentBase64, 'base64')),\n knowledgeBaseId: typeof body.knowledgeBaseId === 'string' && body.knowledgeBaseId.trim() ? body.knowledgeBaseId.trim() : undefined,\n }, client)\n value = { upload }; results = 1\n } else {\n counted = false\n return fail('bad-request', `unknown endpoint ${endpoint}`)\n }\n record({ ok: true, results })\n return { ok: true, value }\n } catch (error) {\n if (counted) record({ ok: false, results: 0 })\n if (signal.aborted) return fail('cancelled', '请求已取消')\n const code = error instanceof ZhihuSearchError ? error.code.toLowerCase().replaceAll('_', '-') : 'internal'\n return fail(code, error instanceof Error ? error.message : '知乎请求失败')\n }\n },\n }\n return {\n ...service,\n run,\n async call(endpoint, payload, signal) {\n if (signal.aborted || lifetime.signal.aborted) return fail('cancelled', '请求已取消')\n try { return await run(combined => service.call(endpoint, payload, combined), signal) }\n catch (error) {\n if (signal.aborted || lifetime.signal.aborted) return fail('cancelled', '请求已取消')\n throw error\n }\n },\n async dispose() {\n lifetime.abort()\n await Promise.allSettled([...active])\n await pendingUsage\n },\n }\n}\n\nexport async function apply(ctx: Context): Promise<void> {\n const host = ctx as Host\n const domain = await ctx.storageDomain.open(zhihuUsageDomainSpec)\n const service = createZhihuService({\n resolveCredential: async () => (await host.credentials.resolve(credentialRef(ZHIHU_CREDENTIAL_REF)))?.value,\n }, createZhihuUsageRecorder(domain.table('daily')), event => {\n const emit = ctx.emit as unknown as (name: string, event: ZhihuSearchExecuted) => void\n emit.call(ctx, ZHIHU_SEARCH_EVENT, event)\n })\n ctx.effect(() => async () => { await service.dispose(); await domain.close() }, 'zhihu.usageDomainClose')\n ctx.provide('zhihu', service)\n ctx.effect(() => registerHostRpc(host, ZHIHU_RPC_CHANNEL, service.call))\n bindZhihuWebSearch(ctx, service)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/zhihu-knowledge.ts","../src/host-rpc.ts","../src/web-search-provider.ts","../src/index.ts"],"sourcesContent":["/**\n * 知乎知识库的管理侧能力:列知识库、上传文件。仅供设置页 RPC 使用,\n * 不暴露为模型工具——上传会把文件送入知乎云端,必须是用户在界面上显式发起。\n *\n * 端点(来源:github.com/klarkxy/zhihu-search,src/zhihu_search/upstream/http_client.py):\n * - 列表:GET /api/v1/knowledge/bases?Scope=all|created|subscribed\n * - 上传:POST /api/v1/knowledge/files(multipart: File + 可选 KnowledgeBaseID),同步解析\n */\nimport {\n parseZhihuEnvelope,\n zhihuFetchJson,\n ZhihuSearchError,\n type ZhihuClientOptions,\n} from './zhihu-client.ts'\n\nexport const ZHIHU_KNOWLEDGE_LIST_VERSION = 1\nexport const ZHIHU_KNOWLEDGE_UPLOAD_VERSION = 1\n/** 设置页 RPC 走 JSON/base64 传输,限额压到 20MB(平台上限 100MB)。 */\nexport const ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES = 20 * 1024 * 1024\nexport const ZHIHU_KNOWLEDGE_UPLOAD_TIMEOUT_MS = 180_000\n\nconst KNOWLEDGE_BASES_PATH = '/api/v1/knowledge/bases'\nconst KNOWLEDGE_FILES_PATH = '/api/v1/knowledge/files'\n\nexport const ZHIHU_KNOWLEDGE_FILE_EXTENSIONS = [\n '.pdf', '.md', '.txt', '.ppt', '.pptx', '.xlsx', '.xls', '.docx', '.doc',\n '.webp', '.png', '.jpg', '.mobi', '.epub', '.csv', '.azw3',\n] as const\n\nconst KNOWLEDGE_CONTENT_TYPES: Record<string, string> = {\n '.pdf': 'application/pdf',\n '.md': 'text/markdown',\n '.txt': 'text/plain',\n '.ppt': 'application/vnd.ms-powerpoint',\n '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n '.xls': 'application/vnd.ms-excel',\n '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n '.doc': 'application/msword',\n '.webp': 'image/webp',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.mobi': 'application/x-mobipocket-ebook',\n '.epub': 'application/epub+zip',\n '.csv': 'text/csv',\n '.azw3': 'application/vnd.amazon.ebook',\n}\n\nexport type ZhihuKnowledgeBase = {\n id: string\n name: string\n relation: string\n visibility: string\n isDefault: boolean\n contentCount: number\n}\n\nexport type ZhihuKnowledgeBaseList = {\n version: typeof ZHIHU_KNOWLEDGE_LIST_VERSION\n bases: ZhihuKnowledgeBase[]\n}\n\nfunction normalizeBase(raw: Record<string, unknown>): ZhihuKnowledgeBase {\n return {\n id: typeof raw.KnowledgeBaseID === 'string' ? raw.KnowledgeBaseID : '',\n name: typeof raw.Name === 'string' && raw.Name.length > 0 ? raw.Name : '(未命名知识库)',\n relation: typeof raw.Relation === 'string' ? raw.Relation : '',\n visibility: typeof raw.Visibility === 'string' ? raw.Visibility : '',\n isDefault: raw.IsDefault === true,\n contentCount: typeof raw.ContentCount === 'number' ? raw.ContentCount : 0,\n }\n}\n\nexport async function listZhihuKnowledgeBases(options: ZhihuClientOptions = {}): Promise<ZhihuKnowledgeBaseList> {\n const body = await zhihuFetchJson(KNOWLEDGE_BASES_PATH, {\n params: { Scope: 'all' },\n }, '知乎知识库列表', options)\n const data = parseZhihuEnvelope(body) as { Items?: unknown }\n const items = Array.isArray(data.Items) ? data.Items : []\n return {\n version: ZHIHU_KNOWLEDGE_LIST_VERSION,\n bases: items\n .filter((item): item is Record<string, unknown> => !!item && typeof item === 'object' && !Array.isArray(item))\n .map(normalizeBase)\n .filter((base) => base.id.length > 0),\n }\n}\n\nexport type ZhihuKnowledgeUploadInput = {\n fileName: string\n data: Uint8Array\n /** 指定目标知识库;缺省进默认库。 */\n knowledgeBaseId?: string\n}\n\nexport type ZhihuKnowledgeUpload = {\n version: typeof ZHIHU_KNOWLEDGE_UPLOAD_VERSION\n knowledgeBaseId: string\n recallContentId: string\n fileName: string\n fileSize: number\n title: string\n abstract: string\n originUrl: string\n}\n\n/** 校验文件名与大小,返回小写扩展名。 */\nexport function checkKnowledgeFile(fileName: string, size: number): string {\n const cleaned = fileName.trim()\n if (!cleaned) throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件名不能为空。')\n // 去掉路径成分,只保留文件名\n const base = cleaned.split(/[\\\\/]/).pop() ?? cleaned\n for (const ch of base) {\n const code = ch.codePointAt(0) ?? 0\n if (code < 32 || code === 127) throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件名不能包含控制字符。')\n }\n if (new TextEncoder().encode(base).length > 255) {\n throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件名不能超过 255 个 UTF-8 字节。')\n }\n if (size <= 0) throw new ZhihuSearchError('BAD_RESPONSE', '知识库文件内容不能为空。')\n if (size > ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES) {\n throw new ZhihuSearchError('BAD_RESPONSE', `知识库文件大小不能超过 ${ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES / 1024 / 1024}MB。`)\n }\n const dot = base.lastIndexOf('.')\n const ext = dot >= 0 ? base.slice(dot).toLowerCase() : ''\n if (!(ZHIHU_KNOWLEDGE_FILE_EXTENSIONS as readonly string[]).includes(ext)) {\n throw new ZhihuSearchError('BAD_RESPONSE', `知识库上传仅支持 ${ZHIHU_KNOWLEDGE_FILE_EXTENSIONS.join('、')}。`)\n }\n return ext\n}\n\nexport async function uploadZhihuKnowledgeFile(\n input: ZhihuKnowledgeUploadInput,\n options: ZhihuClientOptions = {},\n): Promise<ZhihuKnowledgeUpload> {\n const cleaned = (input.fileName.trim().split(/[\\\\/]/).pop() ?? input.fileName.trim())\n const ext = checkKnowledgeFile(input.fileName, input.data.byteLength)\n const form = new FormData()\n if (input.knowledgeBaseId) form.set('KnowledgeBaseID', input.knowledgeBaseId)\n form.set('File', new Blob([input.data.buffer as ArrayBuffer], { type: KNOWLEDGE_CONTENT_TYPES[ext] ?? 'application/octet-stream' }), cleaned)\n const body = await zhihuFetchJson(KNOWLEDGE_FILES_PATH, {\n formData: form,\n }, '知乎知识库上传', { ...options, timeoutMs: options.timeoutMs ?? ZHIHU_KNOWLEDGE_UPLOAD_TIMEOUT_MS })\n const data = parseZhihuEnvelope(body) as Record<string, unknown>\n return {\n version: ZHIHU_KNOWLEDGE_UPLOAD_VERSION,\n knowledgeBaseId: typeof data.KnowledgeBaseID === 'string' ? data.KnowledgeBaseID : '',\n recallContentId: typeof data.RecallContentID === 'string' ? data.RecallContentID : '',\n fileName: typeof data.FileName === 'string' ? data.FileName : cleaned,\n fileSize: typeof data.FileSize === 'number' ? data.FileSize : input.data.byteLength,\n title: typeof data.Title === 'string' ? data.Title : '',\n abstract: typeof data.Abstract === 'string' ? data.Abstract : '',\n originUrl: typeof data.OriginUrl === 'string' ? data.OriginUrl : '',\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\n\nconst CHANNEL_PATTERN = /^\\/[A-Za-z0-9._~-]+$/\nconst ENDPOINT_SEGMENT = /^[A-Za-z0-9_$.-]+$/\nconst MAX_BODY_BYTES = 64 * 1024 * 1024\n\nexport type HostRpcHandler = (endpoint: string, payload: unknown, signal: AbortSignal) => Promise<unknown>\n\nexport type HostRpcContext = {\n webServer: {\n register: (route: {\n kind: 'prefix'\n path: string\n handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>\n }) => () => void\n }\n connection: {\n requestRejection?: (request: IncomingMessage) => number | undefined\n }\n}\n\n/** Standalone copy of manuscript Host RPC registration; this package cannot depend on manuscript. */\nexport function registerHostRpc(ctx: HostRpcContext, channel: string, handler: HostRpcHandler): () => void {\n if (!CHANNEL_PATTERN.test(channel) || channel === '/api') {\n throw new Error(`invalid RPC channel ${JSON.stringify(channel)}`)\n }\n return ctx.webServer.register({\n kind: 'prefix',\n path: channel,\n handler: (req, res) => dispatchHostRpc(ctx, channel, handler, req, res),\n })\n}\n\nfunction endpointFromRpcPath(channel: string, pathname: string): string | undefined {\n if (!pathname.startsWith(`${channel}/`)) return undefined\n const endpoint = pathname.slice(channel.length + 1)\n if (endpoint.split('/').some((segment) => segment === '' || segment === '.' || segment === '..' || !ENDPOINT_SEGMENT.test(segment))) {\n return undefined\n }\n return endpoint\n}\n\nasync function dispatchHostRpc(\n ctx: HostRpcContext,\n channel: string,\n handler: HostRpcHandler,\n req: IncomingMessage,\n res: ServerResponse,\n): Promise<void> {\n if (typeof ctx.connection.requestRejection !== 'function') {\n res.writeHead(503)\n res.end('host authorization policy is unavailable')\n return\n }\n const rejection = ctx.connection.requestRejection(req)\n if (rejection !== undefined) {\n res.writeHead(rejection)\n res.end(rejection === 401 ? 'unauthorized' : 'forbidden')\n return\n }\n const abort = new AbortController()\n res.on('close', () => {\n if (!res.writableEnded) abort.abort()\n })\n const url = new URL(req.url ?? '/', 'http://dsh.internal')\n const endpoint = endpointFromRpcPath(channel, url.pathname)\n if (req.method !== 'POST' || endpoint === undefined) {\n res.writeHead(404)\n res.end('not found')\n return\n }\n const contentType = String(req.headers['content-type'] ?? '').split(';', 1)[0]?.trim().toLowerCase()\n if (contentType !== 'application/json') {\n res.writeHead(415)\n res.end('content type must be application/json')\n return\n }\n const chunks: Buffer[] = []\n let received = 0\n for await (const chunk of req) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n received += buffer.byteLength\n if (received > MAX_BODY_BYTES) {\n res.writeHead(413, { connection: 'close' })\n res.end()\n req.destroy()\n return\n }\n chunks.push(buffer)\n }\n let body: unknown\n try {\n body = JSON.parse(Buffer.concat(chunks).toString('utf8') || 'null')\n } catch {\n res.writeHead(400)\n res.end('body is not JSON')\n return\n }\n const record = body && typeof body === 'object' && !Array.isArray(body) ? body as Record<string, unknown> : {}\n const rpcId = typeof record.rpcId === 'string' ? record.rpcId : 'invalid-request'\n if (record.type !== 'client-request' || record.method !== endpoint) {\n res.writeHead(200, { 'content-type': 'application/json' })\n res.end(JSON.stringify({\n type: 'server-response',\n rpcId,\n result: {\n ok: false,\n error: {\n code: 'gateway/bad-request',\n message: record.method !== endpoint\n ? `method ${JSON.stringify(record.method)} does not match endpoint ${JSON.stringify(endpoint)}`\n : 'invalid client-request message',\n details: { issues: [] },\n },\n },\n }))\n return\n }\n try {\n const result = await handler(endpoint, record.payload, abort.signal)\n res.writeHead(200, { 'content-type': 'application/json' })\n res.end(JSON.stringify({ type: 'server-response', rpcId, result }))\n } catch (error) {\n res.writeHead(500)\n res.end(`handler failure: ${String(error)}`)\n }\n}\n","/**\n * Optional web-search-manager backend. Registers only when this profile already\n * provides `webSearchManager`; Zhihu still works without that plugin.\n * Official model tool remains `web_search`. Dedicated `zhihu_global_search` is unchanged.\n */\nimport { ZHIHU_CREDENTIAL_REF } from './contracts.ts'\nimport { reportExecuted, type ZhihuClientOptions, type ZhihuSearchExecuted } from './zhihu-client.ts'\nimport {\n executeZhihuGlobalSearch,\n ZHIHU_GLOBAL_SEARCH_MAX_COUNT,\n} from './operations.ts'\n\ntype ZhihuWebSearchHost = {\n run<T>(execute: (signal: AbortSignal) => Promise<T>, signal: AbortSignal): Promise<T>\n toolOptions: ZhihuClientOptions & { onExecuted: (event: ZhihuSearchExecuted) => void }\n}\n\nexport const ZHIHU_WEB_SEARCH_ID = 'zhihu-global'\n\nexport const ZHIHU_WEB_SEARCH_DESCRIPTOR = {\n id: ZHIHU_WEB_SEARCH_ID,\n label: '知乎全网搜索',\n description: '融合知乎问答与全网内容,返回可溯源的搜索结果。',\n credentialRef: ZHIHU_CREDENTIAL_REF,\n credentialShared: true,\n credentialHint: '与「知乎资料」共用 Access Secret',\n billing: 'request' as const,\n pricing: '注册可获 5,000 次/天试用额度;超额价格需向平台咨询。',\n pricingUrl: 'https://developer.zhihu.com/',\n signupUrl: 'https://developer.zhihu.com',\n}\n\nexport type ZhihuWebSearchSource = { url: string; title?: string; snippet?: string }\nexport type ZhihuWebSearchResult = { sources: ZhihuWebSearchSource[]; truncated?: boolean }\nexport type ZhihuWebSearchRequest = { query: string; maxResults?: number }\n\nexport type ZhihuWebSearchProvider = {\n readonly id: string\n available(): boolean\n search(request: ZhihuWebSearchRequest, signal?: AbortSignal): Promise<ZhihuWebSearchResult>\n}\n\nexport type ZhihuWebSearchManager = {\n registerSearchProvider(\n descriptor: typeof ZHIHU_WEB_SEARCH_DESCRIPTOR,\n factory: (options: { apiKey?: string; timeoutMs: number }) => ZhihuWebSearchProvider,\n ): () => void\n}\n\nexport type ZhihuWebSearchProviderOptions = ZhihuClientOptions & {\n apiKey?: string\n onExecuted?: (event: ZhihuSearchExecuted) => void\n}\n\nfunction sourceFrom(url: string, title: string, snippet: string): ZhihuWebSearchSource | undefined {\n let parsed: URL\n try { parsed = new URL(url) } catch { return }\n if (!['https:', 'http:'].includes(parsed.protocol) || parsed.username || parsed.password) return\n return {\n url: parsed.href,\n ...(title ? { title: title.slice(0, 1000) } : {}),\n ...(snippet ? { snippet: snippet.slice(0, 8000) } : {}),\n }\n}\n\nfunction isWebSearchManager(value: unknown): value is ZhihuWebSearchManager {\n return !!value && typeof value === 'object' && typeof (value as ZhihuWebSearchManager).registerSearchProvider === 'function'\n}\n\nexport function createZhihuWebSearchProvider(options: ZhihuWebSearchProviderOptions): ZhihuWebSearchProvider {\n const { apiKey, onExecuted, ...client } = options\n return {\n id: ZHIHU_WEB_SEARCH_ID,\n available() { return Boolean(apiKey?.trim()) },\n async search(request, signal) {\n if (!apiKey?.trim()) throw new Error('知乎全网搜索未配置 Access Secret。')\n if (!request.query?.trim() || request.query.length > 4000) throw new Error('查询无效。')\n const count = request.maxResults ?? 5\n if (!Number.isInteger(count) || count < 1 || count > ZHIHU_GLOBAL_SEARCH_MAX_COUNT) {\n throw new Error(`结果数须为 1 至 ${ZHIHU_GLOBAL_SEARCH_MAX_COUNT}。`)\n }\n try {\n signal?.throwIfAborted()\n const result = await executeZhihuGlobalSearch(request.query.trim(), count, 'all', {\n ...client,\n signal,\n env: {},\n resolveCredential: async () => apiKey,\n })\n reportExecuted(onExecuted, { ok: true, results: result.items.length })\n const sources = result.items.flatMap(item => sourceFrom(item.url, item.title, item.summary) ?? [])\n return { sources: sources.slice(0, count), truncated: sources.length > count }\n } catch (error) {\n reportExecuted(onExecuted, { ok: false, results: 0 })\n throw error\n }\n },\n }\n}\n\nexport function registerZhihuGlobalSearchProvider(\n manager: ZhihuWebSearchManager,\n service: ZhihuWebSearchHost,\n): () => void {\n return manager.registerSearchProvider(ZHIHU_WEB_SEARCH_DESCRIPTOR, options => {\n const provider = createZhihuWebSearchProvider({\n ...service.toolOptions,\n apiKey: options.apiKey,\n timeoutMs: options.timeoutMs,\n })\n return {\n id: provider.id,\n available: () => provider.available(),\n search: (request, signal) => service.run(\n combined => provider.search(request, combined),\n signal ?? new AbortController().signal,\n ),\n }\n })\n}\n\n/** Wait for `webSearchManager` if this profile loaded it; no-op otherwise. */\nexport function bindZhihuWebSearch(\n ctx: { inject(deps: readonly string[], apply: (inner: { get(name: string): unknown }) => (() => void) | void): unknown },\n service: ZhihuWebSearchHost,\n): void {\n ctx.inject(['webSearchManager'], (inner) => {\n let manager: unknown\n try { manager = inner.get('webSearchManager') }\n catch { return }\n if (!isWebSearchManager(manager)) return\n return registerZhihuGlobalSearchProvider(manager, service)\n })\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { credentialRef } from '@deepseek-ai/dsh-credentials'\nimport { executeZhihuSearch, ZHIHU_SEARCH_DEFAULT_COUNT } from './search-api.ts'\nimport {\n executeZhihuGlobalSearch, executeZhihuHotList, executeZhihuAsk, executeZhihuKnowledgeSearch,\n normalizeRecallScopes, ZHIHU_ASK_MODELS, ZHIHU_ASK_DEFAULT_MODEL,\n} from './operations.ts'\nimport { listZhihuKnowledgeBases, uploadZhihuKnowledgeFile, ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES } from './zhihu-knowledge.ts'\nimport { type ZhihuClientOptions, type ZhihuSearchExecuted, ZhihuSearchError } from './zhihu-client.ts'\nimport { createZhihuUsageRecorder, resolveDays, zhihuUsageDomainSpec, type ZhihuUsageRecorder } from './usage.ts'\nimport { ZHIHU_RPC_CHANNEL, ZHIHU_CREDENTIAL_REF, ZHIHU_SEARCH_EVENT, type ZhihuRpcResult } from './contracts.ts'\nimport { registerHostRpc, type HostRpcContext } from './host-rpc.ts'\nimport { bindZhihuWebSearch } from './web-search-provider.ts'\nimport { executeZhihuOpenPlatform, resolveZhihuOpenPlatformOperation, ZHIHU_OPEN_PLATFORM_APIS, zhihuOpenPlatformResultCount } from './open-platform.ts'\n\nexport const name = '@klarkxy/dsh-zhihu'\nexport const inject = ['connection', 'credentials', 'storageDomain', 'webServer'] as const\nexport type ZhihuService = {\n call(endpoint: string, payload: unknown, signal: AbortSignal): Promise<ZhihuRpcResult>\n run<T>(execute: (signal: AbortSignal) => Promise<T>, signal: AbortSignal): Promise<T>\n dispose(): Promise<void>\n usageSummary(days: unknown): Promise<{ days: unknown[] }>\n toolOptions: ZhihuClientOptions & { onExecuted: (event: ZhihuSearchExecuted) => void }\n}\n\ntype Host = Context & HostRpcContext & {\n credentials: { resolve: (ref: ReturnType<typeof credentialRef>) => Promise<{ value: string } | undefined> }\n}\nconst fail = (code: string, message: string, details: Record<string, unknown> = {}): ZhihuRpcResult => ({ ok: false, error: { code, message, details } })\n\n/** One shared service for direct UI RPC and optional Tool wrappers. */\nexport function createZhihuService(options: ZhihuClientOptions, usage: ZhihuUsageRecorder, notify: (event: ZhihuSearchExecuted) => void = () => {}): ZhihuService {\n // Serialize read-modify-write counters; concurrent tools must not lose increments.\n let pendingUsage = Promise.resolve()\n const lifetime = new AbortController()\n const active = new Set<Promise<unknown>>()\n const run: ZhihuService['run'] = (execute, signal) => {\n const combined = AbortSignal.any([signal, lifetime.signal])\n const request = Promise.resolve().then(() => { combined.throwIfAborted(); return execute(combined) })\n active.add(request)\n return request.finally(() => active.delete(request))\n }\n const record = (event: ZhihuSearchExecuted) => {\n pendingUsage = pendingUsage.then(() => usage.record(event)).catch(() => {})\n try { notify(event) } catch { /* observer failure does not change a request */ }\n }\n const service = {\n toolOptions: { ...options, onExecuted: record },\n async usageSummary(days: unknown) { await pendingUsage; return { days: await usage.read(resolveDays(days)) } },\n async call(endpoint: string, payload: unknown, signal: AbortSignal): Promise<ZhihuRpcResult> {\n if (signal.aborted) return fail('cancelled', '请求已取消')\n const body = payload && typeof payload === 'object' && !Array.isArray(payload) ? payload as Record<string, unknown> : {}\n const client = { ...options, signal }\n let counted = false\n const operation = resolveZhihuOpenPlatformOperation(endpoint)\n const quotaId = operation ? ZHIHU_OPEN_PLATFORM_APIS[operation].quotaId : undefined\n const metering = quotaId ? { quotaId } : {}\n try {\n if (endpoint === 'usage.summary') { await pendingUsage; return { ok: true, value: { days: await usage.read(resolveDays(body.days)) } } }\n const query = typeof body.query === 'string' ? body.query : ''\n if (['search', 'global.search', 'ask', 'knowledge.search'].includes(endpoint) && (!query.trim() || query.length > 4000)) {\n return fail('bad-request', '查询不超过 4000 字符')\n }\n let value: unknown\n let results = 0\n counted = true\n if (operation) {\n counted = operation !== 'quota'\n const result = await executeZhihuOpenPlatform(operation, payload === undefined ? {} : payload, client)\n value = result; results = zhihuOpenPlatformResultCount(result)\n } else if (endpoint === 'search') {\n const result = await executeZhihuSearch(query, typeof body.count === 'number' ? body.count : ZHIHU_SEARCH_DEFAULT_COUNT, client)\n value = result; results = result.items.length\n } else if (endpoint === 'global.search') {\n const result = await executeZhihuGlobalSearch(query, typeof body.count === 'number' ? body.count : 10,\n body.searchDb === 'realtime' || body.searchDb === 'static' ? body.searchDb : 'all', client)\n value = result; results = result.items.length\n } else if (endpoint === 'hot.list') {\n const result = await executeZhihuHotList(typeof body.limit === 'number' ? body.limit : 10, client)\n value = result; results = result.items.length\n } else if (endpoint === 'ask') {\n const model = (ZHIHU_ASK_MODELS as readonly unknown[]).includes(body.model) ? body.model as typeof ZHIHU_ASK_MODELS[number] : ZHIHU_ASK_DEFAULT_MODEL\n value = await executeZhihuAsk(query, model, client); results = 1\n } else if (endpoint === 'knowledge.search') {\n const result = await executeZhihuKnowledgeSearch(query, typeof body.limit === 'number' ? body.limit : 5, normalizeRecallScopes(body.recallScopes), client)\n value = result; results = result.items.length\n } else if (endpoint === 'knowledge.bases') {\n const result = await listZhihuKnowledgeBases(client); value = result; results = result.bases.length\n } else if (endpoint === 'knowledge.upload') {\n const contentBase64 = typeof body.contentBase64 === 'string' ? body.contentBase64 : ''\n if (!contentBase64) throw new Error('缺少文件内容。')\n if (contentBase64.length > Math.ceil(ZHIHU_KNOWLEDGE_UPLOAD_MAX_BYTES / 3) * 4 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(contentBase64)) {\n return fail('bad-request', '文件内容无效或超过 20 MB')\n }\n const upload = await uploadZhihuKnowledgeFile({\n fileName: typeof body.fileName === 'string' ? body.fileName : '',\n data: new Uint8Array(Buffer.from(contentBase64, 'base64')),\n knowledgeBaseId: typeof body.knowledgeBaseId === 'string' && body.knowledgeBaseId.trim() ? body.knowledgeBaseId.trim() : undefined,\n }, client)\n value = { upload }; results = 1\n } else {\n counted = false\n return fail('bad-request', `unknown endpoint ${endpoint}`)\n }\n if (counted) record({ ok: true, results, ...metering })\n return { ok: true, value }\n } catch (error) {\n if (counted) record({ ok: false, results: 0, ...metering })\n if (signal.aborted) return fail('cancelled', '请求已取消')\n const code = error instanceof ZhihuSearchError ? error.code.toLowerCase().replaceAll('_', '-') : 'internal'\n const details: Record<string, unknown> = {}\n if (error instanceof ZhihuSearchError) {\n for (const key of ['status', 'upstreamCode', 'retryAfter', 'retryable'] as const) {\n if (error[key] !== undefined) details[key] = error[key]\n }\n }\n return fail(code, error instanceof Error ? error.message : '知乎请求失败', details)\n }\n },\n }\n return {\n ...service,\n run,\n async call(endpoint, payload, signal) {\n if (signal.aborted || lifetime.signal.aborted) return fail('cancelled', '请求已取消')\n try { return await run(combined => service.call(endpoint, payload, combined), signal) }\n catch (error) {\n if (signal.aborted || lifetime.signal.aborted) return fail('cancelled', '请求已取消')\n throw error\n }\n },\n async dispose() {\n lifetime.abort()\n await Promise.allSettled([...active])\n await pendingUsage\n },\n }\n}\n\nexport async function apply(ctx: Context): Promise<void> {\n const host = ctx as Host\n const domain = await ctx.storageDomain.open(zhihuUsageDomainSpec)\n const service = createZhihuService({\n resolveCredential: async () => (await host.credentials.resolve(credentialRef(ZHIHU_CREDENTIAL_REF)))?.value,\n }, createZhihuUsageRecorder(domain.table('daily')), event => {\n const emit = ctx.emit as unknown as (name: string, event: ZhihuSearchExecuted) => void\n emit.call(ctx, ZHIHU_SEARCH_EVENT, event)\n })\n ctx.effect(() => async () => { await service.dispose(); await domain.close() }, 'zhihu.usageDomainClose')\n ctx.provide('zhihu', service)\n ctx.effect(() => registerHostRpc(host, ZHIHU_RPC_CHANNEL, service.call))\n bindZhihuWebSearch(ctx, service)\n}\n"],"mappings":"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"}