# @codefusion-cc/sealed 中文文档

规范地址：https://npmcn.com/package/%40codefusion-cc/sealed/

版本：0\.1\.3
npm 元数据更新时间：2026-10-09T13:28:51.281Z
中文译文更新时间：2026-11-10T08:39:25.054Z
软件包许可：MIT

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

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

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

- 包体积（解压后）：38.1 kB，10 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=20
- 运行依赖：1 个
- 首次发布：2026-10-01T14:29:44.386Z
- 最新版本发布：2026-10-09T13:28:51.053Z
- 近 30 天下载量：2131（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：7（近 12 个月 7 个）

## 中文简介

秘密保存在数据库中,由AES-GCM从工人密钥下封入(每个密钥绑入保存地点,可以替换而不会丢失旧密钥),小秘密被封入收件人的X25519公用密钥 s

## 安装

```sh
npm install @codefusion-cc/sealed
```

也可以使用：`pnpm add @codefusion-cc/sealed`、`yarn add @codefusion-cc/sealed`、`bun add @codefusion-cc/sealed`

## README

# @ 编码- cc/ 密封

保密应用程序在自己的数据库中保存(它所调用服务的 API 密钥, 表示人们粘贴到一个 admin 面板)被AES-256-GCM封入数据库从未持有的密钥:一个工人秘密. 副本或导出 数据库中没有任何人被泄露。 WebCrypto 只运行在工人、节点和德诺;它唯一的依赖 实值 `@codefusion-cc/workers-crypto`,用于 base64url 和摘要.

```sh
npm install @codefusion-cc/sealed
```

`@codefusion-cc/sealed/box` 把一个小秘密封在某人的公用钥匙上, 这样他们才打开它 谁不能传达它[下级](https://npmcn.com/package/%40codefusion-cc/sealed/#readme-sealed-to-a-public-key)) (中文(简体) ).

## 钥匙

```sh
codefusion-console cloudflare workers:edit -- sh -c 'npx -p @codefusion-cc/sealed codefusion-sealed-key | npx wrangler secret put CONNECTIONS_KEY'
```

钥匙直接进入秘密 永远不要进入屏幕 Wrangler为这辆装满了硬币 命令,哪个 [`codefusion-console`](https://www.npmjs.com/package/@codefusion-cc/console) 删除退出时 : 没有 `wrangler login` 在麦克.

## 在工人中

```ts
import { loadKeyring } from '@codefusion-cc/sealed'

const keyring = await loadKeyring(env.CONNECTIONS_KEY) // null: no key, or the secret is not one
if (!keyring) throw new Error('Set CONNECTIONS_KEY first')

// Bound to where it is kept: the same text opens only for the same context.
const sealed = await keyring.seal(JSON.stringify({ token }), `connection:${id}`)

const opened = await keyring.open(row.sealed, `connection:${row.id}`)
if (opened.ok) {
  use(JSON.parse(opened.value))
  if (opened.stale) await save(row.id, await keyring.seal(opened.value, `connection:${row.id}`))
} else {
  // 'unknown-key': the key that sealed it is gone; 'tampered': changed, or moved from another row;
  // 'malformed': not a sealed value.
  askForItAgain(opened.reason)
}
```

-   一个密封值是 `v1.<key id>.<iv>.<ciphertext>` (基数64url). 密钥ID是密钥的前8个十六进制数字 SHA-256:它命名密钥而不将其送出,所以一个应用程序可以显示其行需要的密钥.
-   `open` 绝不要为一行人而抛下任何物; `seal` 财务报告和审定财务报表 `open` 当给定一个不是字符串的上下文时, 扔出, 而当平台的 WebCrypto 失败时拒绝(如 `loadKeyring` 是,哪个 然后在下次召唤时再次尝试这个秘密. `tampered` 财务报告和审定财务报表 `unknown-key` 总是指排队, 从来没有停赛.
-   `open` 给出准确的被封存的文本,包含一个主字节顺序标记(U+FEFF)或白空格. 清理封口前有人贴的东西: `value.trim()` 两者都放下,所以从保存的文件复制一个密钥 BOM仍然符合请求标题.
-   密钥在每次隔离时被导入一次,用于同一密文.

## 一个新的密钥

密钥可能先有数个新密钥,除以逗号或白相间. 最新的封印 每把钥匙打开, 和什么更古老的密钥密封打开作为 `stale: true`所以应用程序在读它的时候又封了它.

```sh
codefusion-console cloudflare workers:edit -- npx wrangler secret put CONNECTIONS_KEY   # paste: <new key>,<old key>
```

一旦每行再次被封(每行) `open` 说 `stale: false`),只将新密钥放入密钥. 没有 旧密钥没有退路:它密封的东西必须再输入.

## 从早先的代码移动

前面写入的值 `<iv>.<ciphertext>` (标准基数64,无上下文,如柴油机插件所做的) `open(value, context, { legacy: true })`,总是如所僵化:按所读再封相. 离开 `legacy` 关一次 由于该格式的值无一行约束,因此没有留下.

## 封入公用钥匙

`@codefusion-cc/sealed/box` 是一个通过一个不能读取的服务器的秘密: 页面封存到 使用它的人的公钥(在某人的Mac上的中继器,设备),服务器存储或转发被封件 文本,只有私钥的持有人才能打开。 它的工作像 Libsodium 的密封箱, 在WebCrypto,所以 同样的代码运行在浏览器(Chrimium,Firefox,Safari),节点20和后期,以及Workers.

在收件人上, 在每个开始时: 只有在还没有密钥文件时才会新建密钥 。 旧文件中的新密钥会留下 每个封入到旧公钥的盒子都无法打开,所以其他的(一个它无法读取的文件,一个没有钥匙的文件,a) WebCrypto 失败 停止开始 :

```ts
import { link, readFile, rm, writeFile } from 'node:fs/promises'
import { generateBoxKeys, loadBoxKeys, saveBoxKeys, type BoxKeys } from '@codefusion-cc/sealed/box'

async function recipientKeys(path: string): Promise<BoxKeys> {
  let text: string
  try {
    text = await readFile(path, 'utf8')
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error // unreadable is not missing
    const keys = await generateBoxKeys()
    // It holds the private key. Written whole beside it, then linked in only while the path is still free: a start
    // that dies midway leaves no half-written key file, and two starts at once never write over each other's keys.
    const draft = `${path}.${crypto.randomUUID()}.new`
    await writeFile(draft, await saveBoxKeys(keys), { mode: 0o600, flag: 'wx' })
    try {
      await link(draft, path)
    } catch (error) {
      if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error
      return recipientKeys(path) // another start made them first: use those
    } finally {
      await rm(draft, { force: true })
    }
    return keys
  }
  const keys = await loadBoxKeys(text.trim()) // rejects when WebCrypto fails, rather than saying there are none
  if (!keys) throw new Error(`${path} holds no box keys: move it aside to make new ones`)
  return keys
}

const keys = await recipientKeys(path)
register(keys.publicKey) // 43 characters of base64url: give it to the server, which hands it to the page
```

在页面中,封入服务器提供给它的公钥:

```ts
import { sealBox } from '@codefusion-cc/sealed/box'

const sealed = await sealBox(relay.publicKey, prompt, `terminal:${relay.id}:${promptId}`) // null: not a box public key
```

在接收者上打开服务器转发的内容:

```ts
import { openBox } from '@codefusion-cc/sealed/box'

const opened = await openBox(keys, sealed, `terminal:${relayId}:${promptId}`)
if (opened.ok) run(opened.text) // or opened.bytes
// 'malformed': not a sealed box, or longer than maxBytes (1 MiB unless given);
// 'tampered': changed, sealed to another key, or for another context.
```

-   **它会做什么**:每个印章会制作一对新鲜的X25519密钥;它与收件人密钥一致的秘密去 通过HKDF-SHA256(用两种公用钥匙进行盐分,其信息中的内容)到一次使用的AES-256-GCM密钥. 这个 密封文本为 `box1.<ephemeral public key>.<iv>.<ciphertext>`,每个部分基数64url不粘贴.
-   **A. 背景情况**: 打开框的字符串名称, 如 `seal`上面写着 一个框移动到另一个 上下文(另一个提示,另一个中继)不会打开。 把所有的ID 接收检查.
-   **谁的钥匙**:无论谁交出页面,收件人的公钥决定谁打开盒子. 一个掌上电脑的服务器 打开它自己的密钥 而不是读取页面封条的内容 所以盒子对存储和保存的服务器保密 转发它(它的数据库,它的日志,其中任何一个都漏出),而不是隐藏在钥匙上的。 这很重要, 页面获取或检查密钥的另一种方式(在收件人上显示指纹).
-   **匿名发送者**:一个盒子没有说是谁封的. 谁有公用钥匙,谁可以封起来,那么一个盒子 hold是来自外部的输入:认证谁单独要求它(服务器在转发之前是这样做的).
-   **没有自己的保护**: 同一框为同一上下文再次打开. 使背景独特(a) )并让收件人拒绝它已经运行的id.
-   **钥匙在休息**数字 : `saveBoxKeys` 写私钥的JWK(RFC 8037); 保存在只有所有者阅读的地方. `loadBoxKeys` 返回时为无效,包括两个半个不是一对的JWK,并加载 私人密钥不可提取,除非 `{ extractable: true }` (只需要再保存一次).
-   **错误**数字 : `sealBox` 解析一个不是盒子公钥的收件人为无效(或其中少数 X25519 键之一) - 小型命令,其中不包含任何秘密; `openBox` 永远不要为封存的文本丢弃。 都投给 参数 编程错误给定的(不是字符串的上下文,不是框键的密钥),以及每个 函数,它使用 WebCrypto 拒绝在失败时使用平台本身的错误(旧浏览器中没有 X25519,一个已损坏) 约束:无效, `malformed` 财务报告和审定财务报表 `tampered` 只描述过输入.
-   **小秘密( 暗号)**: a box 是 AES-GCM 信件, 保存在全内存中. `openBox` 拒绝次数超过 `maxBytes` 联 合 国 解码任何内容之前的纯文本( 默认 1 MiB) .

`@codefusion-cc/realtime`账户密钥( e)`packages/realtime/src/accountKeys.ts`在P-256上有一个自己的盒子 使用自己的格式,设备已经将数据封存起来,所以它们留在上面而不是移动到这里.

## 常见问题

### @codefusion-cc/sealed 是什么？

秘密保存在数据库中,由AES-GCM从工人密钥下封入\(每个密钥绑入保存地点,可以替换而不会丢失旧密钥\),小秘密被封入收件人的X25519公用密钥 s

### 如何安装 @codefusion-cc/sealed？

在项目目录运行 npm install @codefusion-cc/sealed，或使用 pnpm add / yarn add / bun add。它还提供命令行工具 codefusion-sealed-key，可以用 npx codefusion-sealed-key 直接运行。

### @codefusion-cc/sealed 支持 TypeScript 吗？

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

### @codefusion-cc/sealed 支持 ESM 还是 CommonJS？

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

### @codefusion-cc/sealed 需要什么版本的 Node\.js？

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

### @codefusion-cc/sealed 可以商用吗？

@codefusion-cc/sealed 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @codefusion-cc/sealed 的下载量有多少？

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

### @codefusion-cc/sealed 还在维护吗？

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

