@expandai/sdk

中文文档
0.22.1发布于 2026/11/07Apache-2.0TypeScriptES Module近 30 天下载 4339

扩展AI 的脚本 SDK 类型

中文使用文档
文档目录14 节
  1. 安装
  2. 认证
  3. 快开始
  4. 保证API
  5. 效力服务
  6. 本地页面和文件
  7. 搜索
  8. 爬行和捕捉预测
  9. 爬行如何找到页面
  10. 断接取取
  11. 保证API
  12. 效力服务
  13. 重审什么
  14. 许可证

@ expandai/ sdk

正式类型SDK 扩展AI API (英语).

建造在 效果,同时拥有一个基于阶级的客户端,用于承诺式使用和 Effect.Service 实现全面一体化.

安装

需要节点20.3或更新.

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

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

npm install @expandai/sdk@staging

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

认证

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

export EXPAND_API_KEY=sk_...

快开始

保证API

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 延时器和投票,并释放这个客户端的连接而不关闭另一个客户端的池. 重复关闭是安全的;以后对一个被关闭的客户端请求拒绝. 效应服务消费者保留现有的范围层清理.

构造器选项 :

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 ——请求超时

效力服务

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:

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。 。 。 .

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

本地模式需要一个 API 密钥并临时公开分享所选内容. 保存的快照之后仍可共享 。 永远不要为未信任的用户提供的 URL 或路径启用 。 见 本地页面和文件 用于设置、文件夹边界、支持输入和出错.

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

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分 见 搜索。 。 。 .

爬行和捕捉预测

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

重放创建密钥返回原命令的 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值,甚至在夸克-模版页面上使用.

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;它们不进行自动重试.

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

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,使用被钉住的快照:

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 函数还开始一页读取。 活页迭代曝光出空长波超时页;项目迭代隐藏.

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

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。 。 。 .

效力服务

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 (英语)

版本与发布记录

@expandai/sdk 共发布 93 个版本,首次发布于 2025/12/11;过去 12 个月发布了 93 个版本。

版本发布日期距今
0.22.1latest2026/11/076 天前
0.22.1-staging.sha-8434d15bda9f9cb443a6c38cf2f86775f84124f2staging2026/11/077 天前
0.22.0-staging.sha-a1a9e9d1d072b40d5ef34041750970692aa4764c2026/11/067 天前
0.22.02026/10/2916 天前
0.22.0-staging.sha-fc5a593e3c04d00b5d03efab021d8ba25df7eee62026/10/2916 天前
0.21.0-staging.sha-948f1fe5d736bbda5446e6424943a7cd01dd7ec02026/10/2916 天前

其他发布通道:staging-superseded → 0.19.0-staging.sha-891e186442846aeaad9291932c179593c669d681,staging → 0.22.1-staging.sha-8434d15bda9f9cb443a6c38cf2f86775f84124f2。

关于 @expandai/sdk 的常见问题

@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 和提交记录判断。