# TypeScript SDK

> 提供 Management API、Content Delivery API 与 Customer API 的类型化客户端，以及针对 Webhooks、预览、SEO 文件与 Edge 的辅助工具。

> Markdown version of https://kanorio.com/zh-CN/developers/sdk. Append `.md` to any developer docs URL for this format. Index: https://kanorio.com/llms.txt · MCP: https://app.kanorio.com/api/mcp
>
> Translated from the English original: https://kanorio.com/en/developers/sdk.md

`@kanorio/sdk` 是一个轻量且完全类型化的客户端，由三个 OpenAPI 文档生成。路径、参数、请求体与响应皆会在编译时进行检查。它可在任何支持 `fetch` 的环境运行：Node.js、Edge Runtime、Deno、Bun 与浏览器。

```bash
npm install @kanorio/sdk
```

## 客户端

| 功能 | API | 凭证 |
|---|---|---|
| `createManagementClient({ token })` | 位于 `https://app.kanorio.com/api/v1` 的 Management API | `knr_pat_` 或 `knr_sa_`。仅限服务器端使用。 |
| `createDeliveryClient({ siteUrl, previewToken? })` | 单个网站的 Content Delivery API | 无，或用于草稿的 `knr_pv_` |
| `createCustomerClient({ siteUrl, token })` | 单个网站的 Customer API | `knr_cat_` |

每个客户端皆具备 `get`、`post`、`put`、`patch` 与 `delete` 方法。路径参数置于 `params`，查询参数置于 `query`，而 JSON 内容则置于 `body`。

```ts
import { createManagementClient } from "@kanorio/sdk";

const kanorio = createManagementClient({ token: process.env.KANORIO_TOKEN! });

const page = await kanorio.get("/sites/{id}/pages/{pageId}", {
  params: { id: "ws_example123", pageId: "pg_example456" },
});
```

`token` 可以是一个函数，让您能在每次请求时获取更新后的令牌。

## 错误处理

非 `2xx` 的响应会抛出 `KanorioApiError`，包含 `code`、`status`、`message` 与 `details`。`retryAfter` 会从 `Retry-After` 标头或 `details.retryAfter` 中填入。

```ts
import { KanorioApiError } from "@kanorio/sdk";

try {
  await kanorio.post("/sites/{id}/posts/{postId}/publish", { params: { id, postId }, body: {} });
} catch (error) {
  if (error instanceof KanorioApiError && error.code === "SITE_NOT_PUBLISHED") {
    await kanorio.post("/sites/{id}/publish", { params: { id }, body: {} });
  } else {
    throw error;
  }
}
```

## 分页

`paginate` 可将任何列表端点转换为异步迭代器，并根据 `nextCursor` 进行处理。`listAll` 则会将所有页面收集至一个数组中。

```ts
import { createDeliveryClient, paginate } from "@kanorio/sdk";

const delivery = createDeliveryClient({ siteUrl: "https://s-xxxxxxxxxxxx.kanorio.com" });

for await (const item of paginate((cursor) =>
  delivery.get("/collections/{key}/items", { params: { key: "projects" }, query: { cursor, limit: 100 } })
)) {
  console.log(item.slug);
}
```

## 辅助工具

| 导入 | 功能说明 |
|---|---|
| `verifyWebhookSignature`, `createRevalidateHandler` | 验证 `X-Kanorio-Signature` 并重新验证 `data.cacheTags`（前缀为 `kanorio:`）。请参阅 [Webhooks](https://kanorio.com/zh-CN/developers/webhooks)。 |
| `cacheTag`, `localizeCacheTags`, `prefixCacheTags` | 构建请求应携带的缓存标签（`cacheTag.collection("blog")`、`cacheTag.item(id)`、`localizeCacheTags(tags, "fr-FR")`），并加上 Webhook 处理程序重新验证时使用的 `kanorio:` 前缀 |
| `seoRewrites({ siteUrl, framework })` | 从您自己的域名提供网站的 sitemap、robots.txt、llms.txt 和 feeds |
| `fetchDeliveryJsonLd({ siteUrl, path })` | 页面的 Schema.org JSON-LD |
| `@kanorio/sdk/edge` › `createKanorioMiddleware` | 应用重定向（精确匹配，接着是 `/*` 通配符）、拦截所有者设置拦截的 AI 爬虫、提供 IndexNow 密钥文件，并在多语言网站中处理语言规则：将主要语言前缀重定向至根目录、提供 `/{prefix}/llms.txt` 和 `/{prefix}/rss.xml`、匹配无前缀的重定向，并在 `evaluate()` 中报告请求的语言环境 |
| `requestLocaleOf`, `localizedPath`, `languageSwitcher` | 从路径名称解析网站 `locales[]`（`GET /site`）中的语言环境、在另一种语言环境中构建相同的路径、列出语言菜单 |
| `buildAlternates` | 根据 `resolvedLocale` / `availableLocales` 为单个页面构建 Canonical 和 `hreflang`，并遵循托管网站的规则（各语言环境自定义 Canonical、`x-default` 指向主要语言环境、后备页面 Canonical 指向主要语言环境） |
| `@kanorio/sdk/preview` › `createPreviewRouteHandler` | 将后台的预览链接转换为草稿模式会话 |
| `@kanorio/sdk/forms` › `forms.client` | 获取表单、其机器人防护验证和上传票据，然后提交 |
| `parseDeliveryCacheTags`, `frameworkCacheTags` | 读取 Content Delivery API 响应中的 `X-Kanorio-Cache-Tags`，可选择原始格式或为您的框架缓存加上前缀 |

## 内容模型的类型

集合是依网站定义的，因此其字段类型来自网站本身。请使用 [CLI](https://kanorio.com/zh-CN/developers/cli) 进行生成：

```bash
npx @kanorio/cli types --site https://s-xxxxxxxxxxxx.kanorio.com --out src/kanorio.d.ts
```

## 版本控制

此 SDK 遵循语义化版本控制。其版本信息会随每次请求发送，以便 Kanorio 在您调用已弃用的操作时发出警告。请参阅 [版本控制](https://kanorio.com/zh-CN/developers/basics/versioning)。
