# @tereo-io/sdk 中文文档

规范地址：https://npmcn.com/package/%40tereo-io/sdk/

版本：0\.5\.0
npm 元数据更新时间：2026-11-02T15:53:16.181Z
中文译文更新时间：2026-11-02T16:05:35.349Z
软件包许可：Apache-2\.0

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

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

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

- 包体积（解压后）：730 kB，385 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：11 个
- 首次发布：2026-10-14T19:53:08.733Z
- 最新版本发布：2026-11-02T15:53:15.780Z
- 已发布版本数：7（近 12 个月 7 个）

## 中文简介

一个SDK，让应用服务通过一个@dianemo/core请求处理程序到达Tereo: auth、files、webhooks和audit

## 安装

```sh
npm install @tereo-io/sdk
```

也可以使用：`pnpm add @tereo-io/sdk`、`yarn add @tereo-io/sdk`、`bun add @tereo-io/sdk`

## README

# @ tereo-io/sdk

SDK应用服务用于访问 [tereo](https://github.com/tereo-io/tereo)： auth、files、webhooks和 审核一组凭据- `client_id` 和 `client_secret` 一个管理员从 `POST /v1/admin/services`.

```sh
npm install @tereo-io/sdk
```

它只是ESM，在Node.js 22上构建和测试，并且需要一个 `ioredis` 客户端(`redis`,下方)。

```ts
import { createCoreClient, requestIdMiddleware } from "@tereo-io/sdk";
import { Redis } from "ioredis";

const core = createCoreClient({
  service: "product-service",          // its slug, as core knows it
  url: process.env.CORE_URL,           // these four default to the env names shown
  clientId: process.env.CORE_CLIENT_ID,
  clientSecret: process.env.CORE_CLIENT_SECRET,
  requestHandlerKey: process.env.REQUEST_HANDLER_KEY,
  redis: new Redis(process.env.REDIS_URL!, { maxRetriesPerRequest: null }),
  outbox: { db: prisma },              // optional: the transactional outbox
});
await core.start();

// What this service owns, and the access it needs, is not sent at boot: the build writes a
// provisioning document (see docs/provisioning.md) and the deploy pipeline hands it to core.

app.use(requestIdMiddleware());
app.use(core.auth.requireAuth);

await core.files.uploadObject("product-images", "a.png", { file, contentType: "image/png" });

// Audit entries and events that must not be lost: in the same transaction as the change.
await prisma.$transaction(async (tx) => {
  const item = await tx.item.create({ data });
  await core.outbox.audit(tx, { userId, action: "CREATE", entityType: "Item", entityId: item.id });
  await core.outbox.emit(tx, { organizationId, eventType: "product.item.created", entityType: "Item", entityId: item.id, data: item });
});

await core.stop();
```

## 发送通知

Core通过一个管理员配置的连接发送消息（首先是电子邮件）。要求 服务的预配文档中的发件人角色 (`access.roles`）; 在它被应用之前，请求会被403拒绝：

```ts
// provisioning document: service.access.roles includes "notification_sender"

// Direct: throws on failure; an idempotencyKey is generated when you give none.
const { id } = await core.notifications.send({
  channel: "email",
  recipients: [{ address: "ops@example.com" }, { userId, as: "cc" }],
  content: { subject: "Order shipped", text: "…", html: "…" },
});
const sent = await core.notifications.get(id); // status and deliveries

// Not to be lost: in the transaction that makes the change; the reaper sends it after commit.
await prisma.$transaction(async (tx) => {
  await tx.order.update({ where: { id: orderId }, data: { shippedAt: new Date() } });
  await core.outbox.notify(tx, { channel: "email", recipients, content });
});
```

`notify` 拒绝未知频道、少于1个或多于50个收件人，或拒绝不包含 `to` 收件人 (一个没有 `as` 算得上 `to`) 立刻。核心 当reaper转发该行时，验证其余部分（允许的发送者、用户、附件）；4 xx 除了401，403，408，409或429死信。

## `createCoreClient(options)`

每个进程一个——第二个调用会被抛出，直到第一个客户端停止。

| 选项 | 默认的 |  |
| --- | --- | --- |
| `service` | (需要) | 服务很糟糕。这个 `source` 其审计条目，以及审计读取的范围为 |
| `url` | `CORE_URL` | 核心的基URL |
| `clientId` / `clientSecret` | `CORE_CLIENT_ID` / `CORE_CLIENT_SECRET` | 从 _添加服务_ 在核心 |
| `requestHandlerKey` | `REQUEST_HANDLER_KEY` | 加密请求处理程序存储的内容; 32个字符 |
| `redis` | (需要) | 一个具有 `maxRetriesPerRequest: null`． 归来电者所有 |
| `production` | `NODE_ENV === "production"` | 生产处理程序优先于其他共享Redis的处理程序 |
| `auth` | `{}` | `publicRoutes`， `allowedClients`， `introspectionCacheTtlSeconds` 和 `defaultTestPermissions` 用于 `auth.requireAuth` ——看 [身份验证](https://github.com/tereo-io/tereo/blob/master/packages/tereo-sdk/docs/auth.md) |
| `eventTypes` | 任何类型 | 事件类型 `webhooks.emit` 和 `outbox.emit` 接受 |
| `outbox` | 无 | 事务性outbox-请参阅 [发件箱](https://github.com/tereo-io/tereo/blob/master/packages/tereo-sdk/docs/outbox.md)。没有它，阅读 `core.outbox` 抛出 |
| `channelPrefix` | 无 | 核心的 `REDIS_KEY_PREFIX`，当它设置一个时：文件缓存在它下面的通道上听到core的无效 |
| `testMode` | `false` | 对于应用程序的测试: 接受 `test-token-…` 令牌和存根 `auth` 查找和 `files` ——看 [测试](https://github.com/tereo-io/tereo/blob/master/packages/tereo-sdk/docs/testing.md)。抛出，除非 `NODE_ENV` 是 `test` 或者 `development`，与 `production: true` |

一个失踪的 `url`， `clientId`， `clientSecret` 或者 `requestHandlerKey` (选项和env都) 抛出 一次，命名该选项及其env变量。

返回的 `CoreClient`：

| 成员 |  |
| --- | --- |
| `auth` | `AuthServiceClient` -令牌自省， `requireAuth`/`requirePermission`/`requireScope`、用户和组织查找。 [文档/ auth.md](https://github.com/tereo-io/tereo/blob/master/packages/tereo-sdk/docs/auth.md) |
| `files` | `FileServiceClient` -对象，存储桶，权限，版本，预签名url，存档，共享，生命周期，多部分。 [文档/ files.md](https://github.com/tereo-io/tereo/blob/master/packages/tereo-sdk/docs/files.md) |
| `webhooks` | `WebhookServiceClient` -最努力事件发射； `createWebhookVerifier` 对于接收者。 [文档/ webhooks.md](https://github.com/tereo-io/tereo/blob/master/packages/tereo-sdk/docs/webhooks.md) |
| `audit` | `AuditLogServiceClient` -尽最大努力写入和读取此服务的条目。 [docs/audit.md](https://github.com/tereo-io/tereo/blob/master/packages/tereo-sdk/docs/audit.md) |
| `notifications` | `NotificationsClient` - - - - - - `send` 一封电子邮件通过核心， `get` 一个带着送货回来。见 [发送通知](https://npmcn.com/package/%40tereo-io/sdk/#readme-sending-notifications) |
| `outbox` | `OutboxClient` -在应用程序自己的事务中编写的审核条目，事件和通知。 [文档/ outbox.md](https://github.com/tereo-io/tereo/blob/master/packages/tereo-sdk/docs/outbox.md) |
| `start()` | 启动请求处理程序、文件缓存的失效订阅服务器和发件箱收割者。开机时呼叫一次 |
| `stop()` | 停止收割者、缓存订阅者和处理程序；然后可能会创建另一个客户机 |

测试- `testMode`的测试令牌和存根，以及无操作客户端——都在 [docs/testing.md](https://github.com/tereo-io/tereo/blob/master/packages/tereo-sdk/docs/testing.md).

## 如何连接

每个电话都要经过一个 `@dianemo/core` 请求处理程序 (`src/handler.ts`) 与一个客户端 核心, `CORE_CLIENT`： OAuth客户端凭据 `${url}/oauth/token`。它的双胞胎， `CORE_PUBLIC_CLIENT` （`<CORE_CLIENT>:public`)，发送与基本验证相同的凭据 自我反省。处理程序的Redis键是前缀 `@tereo-io/sdk:<clientId>`,所以复制的 一个服务共享令牌和速率限制，一个Redis上的两个服务永远不会混合它们。

处理程序重试5xx，429和丢弃的连接 (`ECONNRESET`， `ETIMEDOUT`）. 这是a Retry从不写两次：

-   `audit.log`/`logAsync`/`logBatchAsync` 和 `webhooks.emit`/`emitAsync`/`emitBatchAsync` 发送一个 `idempotencyKey` 每次调用生成一次 (除非调用者给出了一个)，核心重复数据消除了 24小时。
-   创建核心无法重复数据删除- `createShare`， `initiateMultipart`， `createBucket`， `createArchive`， `grantBucketPermission` 和 `restoreObjectVersion` -通过 `CORE_ONCE_CLIENT` （`<CORE_CLIENT>:once`)，它共享令牌，但在5xx或丢失时立即失败 连接，因为core可能已经写过了。一个4xx，包括429，像往常一样重试。

当core应答401缓存的服务时，令牌被撤销或使用密钥签名，core自 旋转- SDK丢弃令牌并使用新令牌重新尝试一次调用。调用的体是 流 (`uploadObject`) 未重试。

呼叫可能做的是服务的供应文档授予的内容-请参阅 [文档/ provisioning.md](https://github.com/tereo-io/tereo/blob/master/packages/tereo-sdk/docs/provisioning.md) 和核心的 [配置](https://github.com/tereo-io/tereo/blob/master/packages/tereo/docs/provisioning.md) 笔记。读取缓存 (自省、用户、 组织，桶，对象元数据)生活在同一个Redis中，在同一个Redis下 `@tereo-io/sdk:<clientId>` 前缀，所以没有服务读取另一个; Redis失败 直达核心。山 `requestIdMiddleware()` 给予彼此 请求一个 `X-Request-ID` 并在处理时将其转发给core。

内核中的错误以 `RequestError`： `code` 是SDK的调用代码 （`FS_0013`)， `httpStatus` 回答的状态核心 (网络故障后未定义) 和 `coreCode` 核心的 `error` 代码（`not_found`， `idempotency_key_conflict`）。 `statusCode` 保持500，什么？ 转发错误的应用程序应该会回答。 `getOriginalStatus(err)` 和 `getOriginalResponseData(err)` 给出状态和身体。在调试时记录4xx (但429)-通常是预期的，如 `getUser` 把404变成 `null` ——以及其他任何错误。认证中间件抛出 `UnauthorizedError` / `ForbiddenError` (包括 `HttpError`） 到应用程序的错误处理程序。核心将拒绝的输入，或者URL或标头无法携带 完好无损，在送出任何东西之前被拒绝 `InvalidRequestInputError` —路径参数，即 空的, `.` 或者 `..`,对象密钥核心按形状拒绝，标记超过核心的限制。每个路径参数 作为一个段发送转义。

请求处理程序及其传输级别类型分别发布为 `@tereo-io/sdk/handler`，因为它们中的一些与sdk级别的类型共享名称。

## 布局

一个包，文件夹按种类，没有每个区域的模块:

| 路径 | 持有 |
| --- | --- |
| `src/index.ts` | 每个出口: `createCoreClient`，然后是发件箱、供应类型、授权、文件、webhook、审计、错误 |
| `src/coreClient.ts` | `createCoreClient` 和 `CoreClientOptions` |
| `src/handler.ts` | 请求处理程序（每个进程一个）； `CORE_CLIENT` / `CORE_PUBLIC_CLIENT`， `requests`,传输级别类型 |
| `src/clients/` | `auth.ts`， `files.ts`， `webhooks.ts`， `audit.ts`， `notifications.ts`， `outbox.ts` |
| `src/templates/` | 一个客户端模板， `tereo`,及其请求id拦截器 |
| `src/requests/` | 请求定义，镜像core的URL区域： `auth/`， `files/`， `webhooks/`， `audit/`， `notifications/` |
| `src/types/` | SDK级别类型，每个区域一个文件 |
| `src/utils/` | 错误、缓存、测试一下令牌、webhook验证、审核助手、outbox表SQL |
| `src/tests/` | 单元测试 |

## 状态

一个包、核心路径上的一个客户端、outbox和预配文档的类型。

这取决于发布的 `@dianemo/core` `^2.0.0`． 中没有 `tereo` 取决于这个 包中。

## 命令

```sh
npm run build   # tsc
npm run check   # tsc --noEmit
npm test        # vitest
npm run clean   # remove dist/
```

## 常见问题

### @tereo-io/sdk 是什么？

一个SDK，让应用服务通过一个@dianemo/core请求处理程序到达Tereo: auth、files、webhooks和audit

### 如何安装 @tereo-io/sdk？

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

### @tereo-io/sdk 支持 TypeScript 吗？

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

### @tereo-io/sdk 支持 ESM 还是 CommonJS？

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

### @tereo-io/sdk 可以商用吗？

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

### @tereo-io/sdk 还在维护吗？

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

