# @expandai/sdk 中文文档

规范地址：https://npmcn.com/package/%40expandai/sdk/

版本：0\.22\.1
npm 元数据更新时间：2026-11-07T06:34:05.988Z
中文译文更新时间：2026-11-14T04:24:36.185Z
软件包许可：Apache-2\.0

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40expandai/sdk
原文对照：https://npmcn.com/package/%40expandai/sdk/?lang=original
项目主页：https://github.com/expandai/expandai-node#readme
源码仓库：https://github.com/expandai/expandai-node

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：1 MB，103 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=20\.3\.0
- 运行依赖：6 个
- 首次发布：2025-12-11T00:38:49.745Z
- 最新版本发布：2026-11-07T06:34:05.816Z
- 近 30 天下载量：4339（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：93（近 12 个月 93 个）

## 中文简介

扩展AI 的脚本 SDK 类型

## 安装

```sh
npm install @expandai/sdk
```

也可以使用：`pnpm add @expandai/sdk`、`yarn add @expandai/sdk`、`bun add @expandai/sdk`

## README

# @ expandai/ sdk

正式类型SDK [扩展AI](https://expand.ai/) API (英语).

建造在 [效果](https://effect.website/),同时拥有一个基于阶级的客户端,用于承诺式使用和 `Effect.Service` 实现全面一体化.

## 安装

需要节点20.3或更新.

```sh
npm install @expandai/sdk
# or
bun add @expandai/sdk
# or
pnpm add @expandai/sdk
```

在不改变生产的情况下可以使用内部中转建筑 `latest` 标签 :

```sh
npm install @expandai/sdk@staging
```

通过客户端的 API URL 传递 `baseUrl`; 选择 npm 标记不会改变默认的生产终点.

## 认证

设定 `EXPAND_API_KEY` 在你的环境中,或者通过 `apiKey` 在构建客户端时明确.

```sh
export EXPAND_API_KEY=sk_...
```

## 快开始

### 保证API

```ts
import { ExpandClient } from '@expandai/sdk'

const expand = new ExpandClient()

try {
    const result = await expand.fetch({ url: 'https://example.com' })
    console.log(result)
} finally {
    await expand.close()
}
```

重新使用客户端用于您的应用程序的寿命, 然后调用 `close()` 在关闭期间。 关闭终止活动请求,结束 Crawl 延时器和投票,并释放这个客户端的连接而不关闭另一个客户端的池. 重复关闭是安全的;以后对一个被关闭的客户端请求拒绝. 效应服务消费者保留现有的范围层清理.

构造器选项 :

```ts
new ExpandClient({
    apiKey: 'xpnd_...',         // defaults to process.env.EXPAND_API_KEY
    baseUrl: 'https://api...',  // defaults to https://api.expand.ai
    timeoutMs: 60_000,          // total wall-clock budget incl. retries
    maxRetries: 2,              // retries transient failures; see "What gets retried"
})
```

出错 :

-   `ExpandClientError` 无效选项( 缺少 API 密钥, 为空) `baseUrl`(中文(简体) )
-   `ExpandClientApiError` ——非-2xxHTTP响应
-   `ExpandClientConnectionError` ——网络故障
-   `ExpandClientTimeoutError` ——请求超时

### 效力服务

```ts
import { NodeRuntime } from '@effect/platform-node'
import { Effect } from 'effect'
import { ExpandService } from '@expandai/sdk'

const program = Effect.gen(function* () {
    const expand = yield* ExpandService
    const result = yield* expand.fetch({ url: 'https://example.com' })
    yield* Effect.log(result)
})

NodeRuntime.runMain(program.pipe(Effect.provide(ExpandService.layer({ apiKey: process.env.EXPAND_API_KEY }))))
```

图层选项( 形状与 `ExpandClientOptions`:

```ts
ExpandService.layer({
    apiKey: 'xpnd_...',         // defaults to process.env.EXPAND_API_KEY
    baseUrl: 'https://api...',  // defaults to https://api.expand.ai
    timeoutMs: 60_000,          // total wall-clock budget incl. retries
    maxRetries: 2,              // retries transient failures; see "What gets retried"
})
```

输入错误 `Effect` 频道 :

-   `ExpandSdkError` 无效选项( 缺少 API 密钥, 为空) `baseUrl`(中文(简体) )
-   `ExpandApiError` ——非-2xxHTTP响应
-   `ExpandConnectionError` ——网络故障
-   `ExpandTimeoutError` ——请求超时

## 本地页面和文件

在节点.js,通过 `{ local: true }` 改为 `fetch()` 或者说 `fetchJson()` 有本地主机 HTTP URL 或文件或文件夹路径。 同一个选项在 `ExpandService`。 。 。 .

```ts
const markdown = await expand.fetch({ url: 'http://localhost:3000' }, { local: true })
const page = await expand.fetchJson({ url: './dist' }, { local: true })
```

本地模式需要一个 API 密钥并临时公开分享所选内容. 保存的快照之后仍可共享 。 永远不要为未信任的用户提供的 URL 或路径启用 。 见 [本地页面和文件](https://expand.ai/docs/fetch/fetching-a-url#local-pages-and-files) 用于设置、文件夹边界、支持输入和出错.

## 搜索

`search()` 在您还没有 URL 时找到回答问题的页面 。 同样的方法 `ExpandService`。 。 。 .

```ts
const { results } = await expand.search({ query: 'how do I rotate a Stripe API key', maxResults: 3 })
```

发送一个 `query` 最多2000个字符 `maxResults` 从 `1` 改为 `10`,默认为 `10`。每种结果都有: `url`, (中文(简体) ), `title`, (中文(简体) ), `excerpt`,以及 `score`最好先说 答复还有搜索的 `id`数字 : `getSearch(id)` 免费读回来,不再搜索。 搜索费1.5分 见 [搜索](https://expand.ai/docs/search)。 。 。 .

## 爬行和捕捉预测

创建和运行命令重放需要调用者所持的一能键. 一次性爬行完成后永久关闭, 失败或取消; 创建一个新的爬行以再次运行 。 活动由自己的简历抵消.

重放创建密钥返回原命令的 Crawl ID, 即使一个成员已经过期 。 读取已过期成员返回404;再播放从不再创建,或开始替换运行.

### 爬行如何找到页面

爬行从每个源 URL 开始,并停留在该 URL 的可注册域及其子域上.

-   **`maxDepth` 从您的 URL 中计数.** `0` 仅是 URL. `1` 添加网站链接的页面和网站地图中的页面. `2` 增加这些链接的页等。 在网站映射中或搜索中发现的页数为一击,因为它们不在您的列表中 。 A 类 `kind: 'sitemap'` 源是例外: 它列出的 URL 是您的, 因此它们从深度 0 开始 。 默认的,50,是整个网站直到 `maxPages`。 。 。 .
-   **`include` 决定最后的结果 而不是爬行者去的地方.** 达到 `/p/**` 从主页上,爬行者打开链接那里的页面,例如 `/` 财务报告和审定财务报表 `/damen`,并遵循其链接。 它不保存这些页, 他们不计算 `maxPages`。 。 。 .
-   **`exclude` 让爬行者离开.** 匹配的页面从未被打开,所以其后面没有通过它找到.
-   **`sync.freshness` 是否检查每一页的更改次数**,例如 `24h`。每张支票是如何做的,由爬行者决定.

`changePolicy.ignore` 从变化比较中删除匹配子树; `changePolicy.volatile` 用稳定的标记代替它们。 这两段保存的页面内容不变。 选择器支持静态标记、类、ID、属性、组合器和结构伪类,例如 `:not`, (中文(简体) ), `:has` 财务报告和审定财务报表 `:nth-child`。相互作用的国家,例如: `:hover`,伪元素,命名命名空间前缀,嵌入 `:has` 财务报告和审定财务报表 `:nth-child(... of ...)` 拒绝。 匹配包括被捕获的阴影子树并使用对大小写敏感的类和ID值,甚至在夸克-模版页面上使用.

```ts
import { Expand } from '@expandai/sdk'

const expand = new Expand({ apiKey: process.env.EXPAND_API_KEY })
const [crawl] = await expand.crawls.create(
    { sources: ['https://example.com/products'], formats: ['markdown', 'stateJson'] },
    { idempotencyKey: 'catalog-import-2026-09' },
)
if (!crawl) throw new Error('Expected a Crawl')

for await (const event of crawl.events()) {
    if (event.type !== 'page.added' && event.type !== 'page.changed') continue
    const capture = expand.captures(event.captureId)
    const state = event.page.stateJson ?? await capture.stateJson()
    for (const evidence of state.evidence) {
        const body = evidence.body !== undefined ? evidence.body : (evidence.bodyUrl ? await expand.fetchJson(evidence.bodyUrl) : undefined)
        // Process body, then persist event.offset in your application.
    }
}
```

`captures(id)` 还揭露 `get()`, (中文(简体) ), `markdown()`, (中文(简体) ), `html()`, (中文(简体) ), `evidence(key)` 财务报告和审定财务报表 `playgroundUrl()`。这些读取存储的捕获,而不是新鲜的页面。 JSON正体 URL 必须属于所配置的 API 源, 并且不能重定向 。 投影读取接受 `signal` 财务报告和审定财务报表 `timeoutMs`;它们不进行自动重试.

目录和版本列表支持单个项目、页面或等待的一页 :

```ts
const list = crawl.pages({ limit: 100, status: 'live' })
const first = await list // { items, nextCursor? }
for await (const page of list.pages()) { /* page.items */ }
for await (const item of list) { /* item.id, item.url */ }
const bounded = await list.collect({ limit: 200 })

const versions = expand.pages('page-id').versions({ limit: 20 })
const diff = await expand.pages('page-id').diff({ from: 'capture-before', to: 'capture-after' })
```

列表实例缓存其首页 。 停止重复为 `break`,或取消读取 `signal`。 。 。 . `crawl.page(id)` 财务报告和审定财务报表 `crawl.pageByUrl(url)` 读取当前目录投影。 页面版本列表使用 `before` 或者说 `at` 历史读取.

`events({ from: '-1' })` 重放保留历史,包括更改、去除和失败。 它不重建当前目录 。 用于完整目录导入或回收 `CrawlOffsetExpiredError`,使用被钉住的快照:

```ts
for await (const batch of crawl.snapshot().pages()) {
    // Apply batch.items, then persist batch.nextOffset.
    // When batch.upToDate is true, that offset is the boundary to resume with crawl.events({ from }).
}
```

`snapshot({ from: savedSnapshotCursor })` 恢复未完成的快照。 快照光标属于 `/snapshot`; 向 `/events` 返回 410。 事件抵消是不透明的和可分类的:准确复制而不是将其转换成数字。 一次性事件和活动传动器停在EOF溪口. 重复读取被夹时返回,除非 `live: true` 已经设定.

事件读取也暴露了限定的服务器页面. 等待一个事件读取返回一页, 包括空接页, 并关闭读取的页 。 继续使用其 `nextOffset`。事件读取时不会在不同的引用中缓存第一页.

每个非活事件请求和控制请求都尊重客户的 `timeoutMs` 它的复习和 `maxRetries` 限制。 明确 `live: true` 读取在瞬间失效时无限期重联,直到取消、从客户端返回或关闭。 标记服务器拒绝 `retryable: false` 停止任一模式. `done()` 民意调查直至完成或取消 `pollIntervalMs` 不得大于2147483647,50以下的值被夹到50ms.

爬行 API 拒绝延长 `ExpandClientApiError` 财务报告和审定财务报表 `ExpandClientError`,与 `status`, (中文(简体) ), `body`, (中文(简体) ), `code`,以及 `retryable` 可用. `CrawlOffsetExpiredError` 仍然是具体的410个错误。 本地验证错误延伸 `ExpandClientError` 结束 `CrawlClientError`。 。 。 .

效果用户可以调用 `yield* expand.crawls.create(request, { idempotencyKey })` 结束 `ExpandService`,然后使用 `status`, (中文(简体) ), `update`, (中文(简体) ), `cancel`,或 `run` 返回的资源。 这些控制方法共享服务的 HTTP 客户端, 重试, 并输入 `ExpandError` 频道. 游行者们, `done()`,并抓取预测当前使用“承诺”接口;“效果”服务尚未映射这些帮助者.

因为这些读物是可以的, `Promise.resolve`, (中文(简体) ), `Promise.all`,或从一个 `async` 函数还开始一页读取。 活页迭代曝光出空长波超时页;项目迭代隐藏.

```ts
const batch = await crawl.events({ from: savedOffset })
if (batch) {
    for (const event of batch.items) { /* process event */ }
    // Persist batch.nextOffset after processing the whole batch.
}
for await (const batch of crawl.events({ live: true }).pages()) {
    // batch.crawlId identifies the partition, including in merged reads.
}
```

合并页面读取 `from: { [crawlId]: offset }`,就像合并项目读。 每回一批属于一个Crawl 并携带了Crawl的 `nextOffset`; 永远不要为不同的爬行重用.

## 断接取取

`batched` 踢出一个工作,并立即返回 `id`. Poll (英语) `getBatched(id)` 直至 `batchedStatus` 已经不再 `RUNNING` 或者说 `QUEUED`。 。 。 .

### 保证API

```ts
import { ExpandClient } from '@expandai/sdk'

const expand = new ExpandClient()

const run = await expand.batched({ urls: ['https://example.com'] })

let status = await expand.getBatched(run.id)
while (status.batchedStatus === 'RUNNING' || status.batchedStatus === 'QUEUED') {
    await new Promise((resolve) => setTimeout(resolve, 1000))
    status = await expand.getBatched(run.id)
}

console.log(status.results)
```

成功结果包括: `data.markdown` jSON国家 `data.json` 当提取成功时默认.

每一个结果都存在 `status` (单位:千美元)`QUEUED`, (中文(简体) ), `RUNNING`, (中文(简体) ), `SUCCEEDED`, (中文(简体) ), `FAILED`,或 `CANCELLED`并与其 `data`。 。 。 .

### 效力服务

```ts
import { NodeRuntime } from '@effect/platform-node'
import { Duration, Effect, Schedule } from 'effect'
import { ExpandService, type GetBatchedResponse } from '@expandai/sdk'

const program = Effect.gen(function* () {
    const expand = yield* ExpandService
    const run = yield* expand.batched({ urls: ['https://example.com'] })
    const final = yield* expand.getBatched(run.id).pipe(
        Effect.repeat(
            Schedule.recurUntil(
                (status: GetBatchedResponse) => status.batchedStatus !== 'RUNNING' && status.batchedStatus !== 'QUEUED',
            ).pipe(Schedule.addDelay(() => Duration.seconds(1))),
        ),
    )
    yield* Effect.log(final.results)
})

NodeRuntime.runMain(program.pipe(Effect.provide(ExpandService.layer({ apiKey: process.env.EXPAND_API_KEY }))))
```

SDK生成一个等效键,并在省略时再用于自动重试. 供应一个稳定 `idempotencyKey` 以复制进程重新启动后分别拨打或拨打的电话。 使用不同有效载荷的密钥返回 `409 BatchedIdempotencyConflict`。 。 。 .

## 重审什么

不是每5xx是短暂的。 其中一些是对您要求的页面的判断——浏览器自己输入了错误文件,或者该页面无法被捕获——再重复请求会重新运行一个完全的捕获以达到相同的答案,在您的超时预算和配额上.

因此服务器声明答案,而不是把它留给一个状态码规则. 地位不明的错误机构(`429`, (中文(简体) ), `500`, (中文(简体) ), `502`, (中文(简体) ), `503`, (中文(简体) ), `504`, (中文(简体) ), `529`携带 `retryable` 布尔,SDK跟着它:

| 回应 | 复试 |
| --- | --- |
| 超时, 连接失败 | 对 |
| `retryable: true` (例如:. `429 TooManyRequests`, (中文(简体) ), `503 ServiceUnavailable`, (中文(简体) ), `529 FetchCapacityTimeout`(中文(简体) ) | 对 |
| `retryable: false` (例如:. `502 FetchNavigationFailed`, (中文(简体) ), `502 FetchCaptureFailed`, (中文(简体) ), `504 FetchCaptureTimeout`(中文(简体) ) | 没有 |
| 裁决标记为无 `retryable` 字段 - `409 BatchedIdempotencyConflict`, (中文(简体) ), `409 BatchedCancellationConflict`, (中文(简体) ), `502 FetchNavigationFailed`, (中文(简体) ), `502 FetchCaptureFailed`, (中文(简体) ), `504 FetchCaptureTimeout` | 没有 |
| `408`, (中文(简体) ), `429`,其他 `5xx` 没有 `retryable` 字段 | 对 |
| 任何其他非-2xx | 没有 |

因为判决在身体中进行,所以新式错误课不需要SDK升级——这个未识别错误说 `retryable: false` 至今仍未重审.

当回复时 `Retry-After`,下一次尝试至少要等那么长的时间——重新激起,所以一批被一并拒绝的客户不会被锁住而回来. `timeoutMs` 仍然限制整个操作, 重复和等待包含.

## 许可证

[Apache 2.0 (英语)](https://npmcn.com/package/%40expandai/sdk/LICENSE)

## 常见问题

### @expandai/sdk 是什么？

扩展AI 的脚本 SDK 类型

### 如何安装 @expandai/sdk？

在项目目录运行 npm install @expandai/sdk，或使用 pnpm add / yarn add / bun add。

### @expandai/sdk 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @expandai/sdk 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @expandai/sdk 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=20\.3\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @expandai/sdk 可以商用吗？

@expandai/sdk 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @expandai/sdk 的下载量有多少？

根据 npm 官方下载统计，@expandai/sdk 在 2026/10/14 – 2026/11/12 这 30 天内被下载 4,339 次，日均约 145 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @expandai/sdk 还在维护吗？

最新版本 0\.22\.1 发布于 2026/11/07（6 天前）；至今共发布 93 个版本，其中过去 12 个月发布了 93 个；首次发布于 2025/12/11。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

