zeative/zpi-sdk

GitHub: zeative/zpi-sdk

zpi-sdk 是一个零依赖的通用 TypeScript SDK,为 Zapi 数据抓取平台提供统一的 API 调用、流式传输、批量任务及 MCP 工具集成能力。

Stars: 3 | Forks: 1


zpi-sdk - Universal TypeScript SDK for the Zapi (Zest API) scraper platform

zpi-sdk — 适用于 Zapi (Zest API) 抓取平台的通用 TypeScript SDK


NPM Version NPM Downloads NPM Downloads TypeScript 7
License: MIT Zero dependencies Runtimes GitHub Stars GitHub Forks

zpi-sdk 是一个通用、零依赖、API-key 优先的 TypeScript 客户端,专为 Zapi (Zest API) 抓取平台打造。只需构建一个 ZpiClient, 即可端到端调用任何抓取器——支持单次调用、流式传输或批量调用——并提供完整的类型定义和结构化的 错误层级。所有操作都通过单个可注入的 fetch 接口运行,因此同一套构建代码 可以在 Node、Bun、Deno 和浏览器中运行。

[快速开始](#quick-start)  •  [为什么选择 zpi-sdk](#why-zpi-sdk)  •  [安装](#install)  •  [你可以构建什么](#what-you-can-build)  •  [错误处理](#error-handling)  •  [运行环境](#runtime-support)  •  [文档](https://zpi.web.id/docs)

## 快速开始 从 [zpi.web.id](https://zpi.web.id) 获取 API key,构建一个客户端,然后调用任何抓取器—— `run()` 会直接返回解包后的结果数据: ``` import { ZpiClient } from 'zpi-sdk' const client = new ZpiClient({ apiKey: 'zpi_...' }) const data = await client.run('social:instagram', 'profile', { username: 'instagram' }) console.log(data) ``` 这就是全部的集成过程——**无需选择 HTTP method,也无需学习路径模板**: - SDK 会在首次请求时发送正确的动词(GET/POST),并在进程范围内按 endpoint 记住它。将 codegen 的表传递给 `client.useMethods(ZPI_METHODS)`,它就无需再进行询问。 - endpoint 带有像 `resolve/:url` 这样的路径参数?只需将 `url` 放入参数对象中即可——就这么简单。`run('bypass-tools:encurtador', 'resolve', { url: '...' })` 和 `run('bypass-tools:encurtador', 'resolve/:url', { url: '...' })` 都能正常工作。 ## 结合 AI 构建 zpi-sdk 在 `zpi-sdk/mcp` 子路径下内置了 **MCP 客户端**,因此 AI agent 可以发现并将每个抓取器作为 MCP 工具进行调用。它通过远程的 `/mcp` Streamable-HTTP 服务器进行 JSON-RPC 通信——纯手工打造,因此保持了**零依赖**: ``` import { createMcpClient } from 'zpi-sdk/mcp' const mcp = createMcpClient({ apiKey: 'zpi_...' }) const tools = await mcp.listTools() // handshake runs lazily on first call const result = await mcp.callTool('run_scraper', { /* tool args */ }) ``` `mcp` 模块永远不会从根入口加载,因此核心库保持了精简。查看完整指南 → **[zpi.web.id/docs](https://zpi.web.id/docs)**。 ## 为什么选择 zpi-sdk - **零依赖** — 没有运行时依赖,没有 Node 内置模块;一个可注入的 `fetch` 接口即可支持从 Node 到浏览器的各种运行环境。 - **一个方法,涵盖所有抓取器** — `client.run('social:instagram', 'profile', params)` 涵盖了整个目录;无需学习针对特定抓取器的包装器。 - **零繁琐配置** — 无需猜测 `{ method: 'GET' }`(按 endpoint 自动检测并记忆),路径参数(`/:id`, `/:url`)只是 `params` 中的常规字段。 - **类型化的错误层级** — 每次失败都是一个 `ZpiError` 子类(`ZpiRateLimitError`、`ZpiPlanGateError` 等),并带有如 `retryAfterSec` 和 `upgradeUrl` 这样的类型化字段。无需猜测状态码。 - **开箱即用的流式传输** — `client.stream(…)` 返回 SSE 事件的 async iterable,通过 `body.getReader()` 读取,因此可以在任何地方进行增量流式传输。 - **批量任务** — 提交多个 item,通过带有进度回调的 `job.wait()` 等待;提交时自动复用 `Idempotency-Key`,因此重试永远不会创建重复的任务。 - **公共目录发现** — 无需认证即可列出抓取器、分类、endpoint schema 和统计信息。 - **内置 Webhook 验证** — `zpi-sdk/webhooks` 验证 `X-Zpi-Signature`(HMAC-SHA256,时序安全)并返回类型化的事件。 - **类型化 codegen** — `npx zpi codegen` 从实时目录生成针对特定抓取器的绑定,通过完整的自动补全缩小 `run()` 参数的范围。 - **安全的重试机制** — 仅重试网络错误和 `429/502/503/504`(指数退避 + 抖动);在没有 `idempotencyKey` 的情况下,永远不会盲目重试 POST 请求。API key 会从每个错误和日志中隐去。 ## 安装 ``` npm i zpi-sdk # or: pnpm add zpi-sdk • yarn add zpi-sdk • bun add zpi-sdk ``` 要求 **Node.js v20+**。Deno 无需安装步骤——通过 `npm:` 说明符导入即可: ``` import { ZpiClient } from 'npm:zpi-sdk' ``` 零运行时依赖,提供包含 `.d.ts` + `.d.cts` 类型的双模式 ESM/CJS 支持,并附带用于 codegen 的 `bin` (`zpi`)。 除了 API key 之外,所有配置都是可选的: ``` const client = new ZpiClient({ apiKey: 'zpi_...', baseURL: 'https://api.zpi.web.id', // override the default base URL timeoutMs: 30_000, // per-request timeout maxRetries: 2, // retry budget for retryable failures fetch: globalThis.fetch, // inject your own fetch (tests, proxies, edge runtimes) }) ``` ## 你可以构建什么 ### 运行任意抓取器 ``` const profile = await client.run('social:instagram', 'profile', { username: 'instagram' }) const video = await client.run('downloader:tiktok', 'video', { url: 'https://tiktok.com/...' }) const gold = await client.run('finance:goldprice', 'latest', {}) ``` ### 流式传输 对于分块 / SSE endpoint,迭代由 `client.stream(...)` 返回的 async iterable: ``` for await (const event of client.stream('ai:chat', 'completions', { prompt: 'hi' })) { // StreamEvent = SseEvent ({ event?, data, id? }) | string console.log(typeof event === 'string' ? event : event.data) } ``` ### 批量任务 一次性提交多个 item,然后通过 `wait()` 等待完成,并支持可选的进度报告: ``` const job = await client.bulk.submit('social:instagram', 'profile', [ { url: 'https://instagram.com/a' }, { url: 'https://instagram.com/b' }, ]) const result = await job.wait({ onProgress: (j) => console.log(j.succeeded, '/', j.total), }) for (const item of result.items ?? []) { console.log(item.status, item.data ?? item.error) } ``` ### 目录发现(公开,无需认证) ``` const { items } = await client.catalog.list({ cat: 'social', limit: 20 }) const detail = await client.catalog.get('social:instagram') const schema = await client.catalog.schema('social:instagram', 'profile') const stats = await client.catalog.stats('social:instagram') ``` ### 处理 Webhook 使用零依赖的 `zpi-sdk/webhooks` 助手验证并解析传入的 webhook 投递(`bulk.completed`、`quota.warning`、`request.error` 等)——它使用 Web Crypto HMAC 进行时序安全的比较,因此可以在 Node、Bun、Deno 和边缘 worker 上运行: ``` import { parseWebhook } from 'zpi-sdk/webhooks' // In your HTTP handler — pass the RAW body string, not the parsed JSON: const event = await parseWebhook(rawBody, { signature: req.headers['x-zpi-signature'], secret: process.env.ZPI_WEBHOOK_SECRET, }) // → { id, event: 'bulk.completed' | …, data, deliveredAt } // Throws ZpiWebhookVerifyError on a bad signature or malformed payload. ``` ### 类型化 codegen 从**实时**目录生成针对特定抓取器的绑定—— `run()` 的参数将获得完整的自动补全: ``` npx zpi codegen # → ./zpi-sdk.gen.d.ts npx zpi codegen --out ./types/zpi.gen.d.ts --filter social ``` 输出**仅包含类型**(零运行时导入);当目录发生变动时,可随时重新生成。 ## 错误处理 每次失败都会抛出 `ZpiError`(或其子类),携带 `status`、`code?`、`raw` 和 `requestId?` ——你可以根据类进行捕获和分支处理: ``` import { ZpiClient, ZpiPlanGateError, ZpiRateLimitError, ZpiError } from 'zpi-sdk' try { await client.run('social:instagram', 'profile', { username: 'instagram' }) } catch (e) { if (e instanceof ZpiPlanGateError) console.log('upgrade required:', e.requiredPlan, e.upgradeUrl) else if (e instanceof ZpiRateLimitError) console.log('retry after', e.retryAfterSec, 's') else if (e instanceof ZpiError) console.log('zpi error:', e.status, e.code, e.raw) } ``` | 类 | 触发时机 | 重要字段 | | --- | --- | --- | | `ZpiAuthError` | API key 缺失/无效 (401) | — | | `ZpiPlanGateError` | endpoint 需要更高级别的套餐 (403) | `requiredPlan`, `upgradeUrl` | | `ZpiRateLimitError` | 触发限流 (429) | `limit`, `used`, `window`, `retryAfterSec` | | `ZpiInvalidParamsError` | 参数验证失败 (400/422) | `errors[]` | | `ZpiExecError` | 抓取器已运行但失败 | `error`, `errors`, `context` | | `ZpiNetworkError` / `ZpiTimeoutError` / `ZpiAbortError` | 传输失败 / 超时 / 中止 | `cause` | | `ZpiMcpError` | 来自 `/mcp` 的 JSON-RPC 错误 | `code`, `data` | ## 运行环境支持 zpi-sdk 提供了双模式 ESM/CJS 入口点,并包含针对这两种模块系统的类型声明,已验证可在以下环境加载: | 运行环境 | ESM | CJS | | ------- | --- | --- | | Node.js `>=20` | ✅ | ✅ | | Bun | ✅ | ✅ | | Deno (`npm:` specifier) | ✅ | ✅ | | Browser | ✅ | — | 包管理器:支持 **npm**、**pnpm**、**yarn** 和 **bun**。 ## 文档 - 🌐 [**zpi.web.id/docs**](https://zpi.web.id/docs) — 完整的文档网站:指南、API 参考和配方 - 🧭 [**zpi.web.id/apis**](https://zpi.web.id/apis) — 浏览实时的抓取器目录 - 🤖 [**MCP 客户端**](https://zpi.web.id/docs) — 将每个抓取器作为 MCP 工具接入你的 AI agent - 📝 [**更新日志**](./.changeset) — 待发布的说明 ## 问题与反馈 遇到问题或有功能建议?请提交一个 [issue](https://github.com/zeative/zpi-sdk/issues)。 - [请我喝杯咖啡 ☕](https://saweria.co/zaadevofc) • [Ko-Fi](https://ko-fi.com/zaadevofc) • [Trakteer](https://trakteer.id/zaadevofc) - ⭐ 在 GitHub 上为该仓库点个 Star ## 许可证 基于 **MIT License** 分发。详情请参阅 [`LICENSE`](https://github.com/zeative/zpi-sdk/blob/main/LICENSE)。

zpi-sdk Copyright © 2026 zaadevofc. All rights reserved.

标签:API客户端, MITM代理, TypeScript, 安全插件, 自动化攻击, 零依赖