{"_id":"@buddhilive/dsh-web-fetch-http","name":"@buddhilive/dsh-web-fetch-http","dist-tags":{"alpha":"0.1.2-alpha.3","latest":"0.1.2-alpha.3"},"versions":{"0.1.2-alpha.3":{"name":"@buddhilive/dsh-web-fetch-http","description":"Anonymous public HTTP(S) fetch provider for the DeepSeek Harness web capability seam (ctx.web)","version":"0.1.2-alpha.3","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/web/web-fetch-http"},"type":"module","main":"lib/index.js","types":"lib/types/index.d.ts","exports":{".":{"types":"./lib/types/index.d.ts","default":"./lib/index.js"},"./invariant":{"types":"./lib/types/invariant.d.ts","default":"./lib/invariant.js"},"./src/*":"./src/*","./package.json":"./package.json"},"license":"MIT","peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@buddhilive/dsh-timeout":"^0.1.2-alpha.3","@buddhilive/dsh-invariants":"^0.1.2-alpha.3","@buddhilive/dsh-web":"^0.1.2-alpha.3"},"dependencies":{"ipaddr.js":"^2.5.0","undici":"^8.10.0","@deepseek-ai/schemastery":"^3.18.2"},"devDependencies":{"@buddhilive/dsh-invariants":"^0.1.2-alpha.3","@deepseek-ai/cordis":"^4.0.2","@buddhilive/dsh-timeout":"^0.1.2-alpha.3","@buddhilive/dsh-web":"^0.1.2-alpha.3"},"_id":"@buddhilive/dsh-web-fetch-http@0.1.2-alpha.3","bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","_integrity":"sha512-LOMAuuKdXx34RQATk6jh+PzHtQjjdTEbe8BB8+U25okT0+64SdlxbYJkeu2NO0si8s9gwKccZRpP0zFD6hxmZw==","_resolved":"C:\\DevDojo\\Buddhi\\buddhi-ai-harness\\dist\\npm\\buddhilive-dsh-web-fetch-http-0.1.2-alpha.3.tgz","_from":"file:C:/DevDojo/Buddhi/buddhi-ai-harness/dist/npm/buddhilive-dsh-web-fetch-http-0.1.2-alpha.3.tgz","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-LOMAuuKdXx34RQATk6jh+PzHtQjjdTEbe8BB8+U25okT0+64SdlxbYJkeu2NO0si8s9gwKccZRpP0zFD6hxmZw==","shasum":"78bcda226c10dbfa029080b2aeb365044ca889e7","tarball":"https://registry.npmjs.org/@buddhilive/dsh-web-fetch-http/-/dsh-web-fetch-http-0.1.2-alpha.3.tgz","fileCount":12,"unpackedSize":57866,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCmKXpUY7o3jVRdLzdna1/2RV9Qb2DfgeA/sJ6X/awqawIgb7f7PgSTn1JXCJqr014ttsvCB1h3QMcJYIHYO31J+uA="}]},"_npmUser":{"name":"buddhilive","email":"visitbudkavin@gmail.com"},"directories":{},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-web-fetch-http_0.1.2-alpha.3_1788165955163_0.759037212648829"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-31T08:45:54.955Z","0.1.2-alpha.3":"2026-08-31T08:45:55.287Z","modified":"2026-08-31T08:45:55.530Z"},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"description":"Anonymous public HTTP(S) fetch provider for the DeepSeek Harness web capability seam (ctx.web)","homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/web/web-fetch-http"},"bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"license":"MIT","readme":"---\ndescription: \"ctx.web 的匿名公共 HTTP(S) 抓取后端：部署方如何挂载有界、安全的 URL 抓取，含同源重定向与仅文本解码。\"\nkind: \"package-reference\"\n---\n\n# @buddhilive/dsh-web-fetch-http\n\n[English](README.md) | 中文\n\n## 概述\n\n有了 `dsh-web-fetch-http`，harness 可以通过 web 服务（`ctx.web`）抓取公共 HTTP(S) 页面，并在不发送凭据的情况下获得状态码与有界、解码后的内容。当组合需要 URL 校验、公开地址解析、连接固定、仅同源重定向、字节和字符上限及显式产品 `User-Agent` 时选择它。它把非 2xx 响应作为结果而非错误返回，并拒绝非公开目标、二进制数据与不受支持的内容类型。面向模型的 `web_fetch` 工具位于 `dsh-tool-web`，由它渲染本提供方的正文。\n\n## 目录\n\n- [使用本包](#use-this-package)\n- [理解实现](#understand-the-implementation)\n- [进一步探索](#further-exploration)\n- [模型体验](#model-experience)\n- [已知限制与延期工作](#known-limitations-and-deferred-work)\n- [开发备注](#dev-note)\n\n-----\n\n<a id=\"use-this-package\"></a>\n## 使用本包\n\n在已加载 web 服务的组合中挂载本提供方；它以 `http` 抓取提供方身份注册，因此当它是唯一可用的抓取后端时，`ctx.web.fetch()` 会自动解析到它——也可以用 `fetchProvider: http` 固定。\n\n### 何时选择\n\n当部署必须以有界输出和安全传输抓取公共页面时选择此后端：不发送凭据，每个已解析地址必须是公共地址，每次连接都固定到已校验的地址集合，重定向无法逃出源站，每个响应都有上限。\n\n### 最小配置\n\n加载 web 服务与本提供方；可配置上限都有安全默认值，并在插件构造时验证，因此无效值会响亮地失败，而不是构造出上限荒谬的提供方。URL 安全上限固定为 2,048 个字符。\n\n```yaml\n- name: '@buddhilive/dsh-web'\n- name: '@buddhilive/dsh-web-fetch-http'\n```\n\n| 字段 | 默认值 | 含义 |\n|---|---|---|\n| `maxResponseBytes` | `5,000,000` | 响应主体最大字节数 |\n| `maxBodyChars` | `100,000` | 解码主体最大字符数 |\n| `timeoutMs` | `30,000` | 抓取超时——资源兜底，不是面向模型的工具预算 |\n| `maxRedirects` | `5` | 同源重定向最大跳数（`0` 表示不跟随） |\n| `userAgent` | `deepseek-harness/…` | 每次请求发送的 `User-Agent` 标头 |\n\n生成的[配置目录](../../../docs/config-catalog.zh.md#buddhilivedsh-web-fetch-http)是每个受支持字段及其 JSDoc 的穷尽式真源。\n\n### 抓取返回什么\n\n成功调用产生 `WebFetchResult`：允许的重定向之后的最终 URL、HTTP 状态码、分类为 `html` 或 `text` 的解码正文，以及 `truncated` 标志。非 2xx 响应是结果而非错误——状态码是被抓取资源状态的一部分；`WebError` 只用于无法安全获取或表示资源的失败。\n\n```text\nconst page = await ctx.web.fetch({ url: 'https://example.com' })\n// page.body.kind === 'html' | 'text'; page.statusCode === 200 | 404 | ...\n```\n\n### 传输行为\n\n提供方保持请求匿名且有界：只接受不含内嵌凭据且不超过 2,048 个字符的 `http:` 与 `https:` URL。它只解析一次主机名；只要结果中有任何 IPv4 或 IPv6 地址不是公共单播地址，就拒绝整个结果，并把连接固定到已校验的地址集合。IPv6 检查会发现活动 DNS64 前缀，并拒绝指向非公开 IPv4 的转换地址。每次同源重定向都会重复解析与固定；跨源重定向会失败并要求重新调用。提供方还强制执行字节、字符、跳数和时间上限，拒绝不支持的内容类型，并发送显式产品 `User-Agent`。\n\n### 失败与恢复\n\n失败抛出携带可按机器路由 code 的 `WebError`：`WEB_INVALID_URL`、`WEB_BLOCKED_URL`、`WEB_FETCH_TOO_LARGE`、`WEB_FETCH_TIMEOUT`、`WEB_REDIRECT_BLOCKED`、`WEB_UNSUPPORTED_CONTENT_TYPE`、`WEB_ABORTED` 或 `WEB_PROVIDER_ERROR`。直接调用方可以按 code 路由；面向模型的 `web_fetch` 工具会在自己的错误包装层内把失败文本呈现给模型。\n\n-----\n\n<a id=\"understand-the-implementation\"></a>\n## 理解实现\n\n<details>\n<summary>实现细节——点击展开</summary>\n\n本节解释提供方背后的设计决策；可观察行为已在[使用本包](#use-this-package)中完整说明。\n\n### 设计理念\n\n本包建立在一个分离与一个分层超时之上：\n\n- **安全获取与呈现分离。** 本提供方拥有 URL 校验、公开地址强制规则、连接固定、HTTP 传输、重定向策略、上限、charset 解码与二进制拒绝；`dsh-tool-web` 拥有 HTML→markdown 与截断格式化。非 2xx 响应是数据，不是失败。\n- **两层超时。** 提供方的 `timeoutMs` 是直接 `ctx.web.fetch()` 调用方的资源兜底；面向模型的工具调用预算属于 `dsh-tool-call-timeout-policy`，由它触发 `exec.signal`。外层截止期限先到时，提供方报告 `WEB_ABORTED`，策略再以 `TOOL_TIMEOUT` 替换；因此 `WEB_FETCH_TIMEOUT` 标识的是提供方预算耗尽的直接服务调用方。\n\n### 源码地图\n\n| 文件 | 职责 |\n|---|---|\n| [`src/index.ts`](src/index.ts) | 插件入口：配置 schema、上限验证、提供方注册 |\n| [`src/provider.ts`](src/provider.ts) | `HttpFetchProvider`：固定连接、重定向跟随、有界读取、charset 解码 |\n| [`src/network.ts`](src/network.ts) | 公开地址解析、DNS64 发现与连接固定 |\n| [`src/policy.ts`](src/policy.ts) | URL 校验、同源检查、内容类型分类、charset 解析 |\n| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件（无运行时不变式；上限在提供方处强制执行） |\n\n### 读取路径\n\n抓取先校验 URL，只解析一次主机名，结果中只要有非公开地址就拒绝，并把连接固定到已接受地址。每次同源重定向都重复该检查；跨源重定向或非公开目标在接收响应字节前失败。最终响应按 `Content-Type` 分类、依声明的 charset 解码，并在字节上限内读取；解码后的文本再截断到字符上限。\n\n</details>\n\n-----\n\n<a id=\"further-exploration\"></a>\n## 进一步探索\n\n当包级约定不够用时阅读以下页面。它们从共享词汇逐步进入服务、面向模型的工具与设计依据。\n\n- [web 子系统](../../../docs/subsystems/web.zh.md)——穷尽式的抓取请求／结果词汇与错误码。\n- [web 包映射](../README.zh.md)——六包家族与各角色。\n- [dsh-web](../web/README.zh.md)——本提供方注册进入的 web 服务。\n- [dsh-tool-web](../tool-web/README.zh.md)——渲染本提供方正文的面向模型 `web_fetch` 工具。\n- [生成配置目录](../../../docs/config-catalog.zh.md#buddhilivedsh-web-fetch-http)——每个受支持配置字段及其源声明。\n- [web 能力 seam 决策](../../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.zh.md)——搜索与抓取为何共用一项提供方选择服务。\n\n-----\n\n<a id=\"model-experience\"></a>\n## 模型体验\n\n间接地，通过 `dsh-tool-web`：该工具把本提供方经 `maxBodyChars` 限制的解码文本或由 HTML 转换得到的 markdown 置于抓取结果包装层内，而重定向、标头与传输上限保持隐藏。\n\n#### KV Cache 影响\n\n不会直接导致 KV Cache 失效；请求前缀变更由上述消费方负责。\n\n## 已知限制与延期工作\n\n<a id=\"known-limitations-and-deferred-work\"></a>\n\n\n这些限制说明提供方何时不安全或不合适。它们是当前包约束。\n\n- **只解码文本内容**——包括 html/xhtml 与 `text/*` 加 JSON/XML 家族；缺少 `Content-Type` 或任何二进制类型都会抛出 `WEB_UNSUPPORTED_CONTENT_TYPE`，可提取文本的 PDF 解码属于明确的延期工作。\n- **charset 只来自 `Content-Type` 标头**（默认 UTF-8）——HTML `<meta charset>` 声明会被忽略；声明但无法识别的 charset 标签会抛出异常，而非回退。\n\n<a id=\"dev-note\"></a>\n### 开发备注\n\n<details>\n<summary>维护者的工作上下文——点击展开</summary>\n\n无。\n\n</details>\n","readmeFilename":"README.zh.md","_rev":"1-f49648a0146c340e7098997a904b37a4"}