# @eternl/hub-core 中文文档

规范地址：https://npmcn.com/package/%40eternl/hub-core/

版本：0\.55\.0
npm 元数据更新时间：2026-11-10T15:50:22.469Z
中文译文更新时间：2026-11-14T01:15:22.045Z
软件包许可：BUSL-1\.1

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

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

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

- 包体积（解压后）：338 kB，67 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：0 个
- peer 依赖：@nats-io/nats-core 3\.4\.0
- 首次发布：2026-05-08T13:46:52.839Z
- 最新版本发布：2026-11-10T15:50:21.853Z
- 近 30 天下载量：2619（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：66（近 12 个月 66 个）

## 中文简介

Eternl Hub SDKs的共享基础设施.

## 安装

```sh
npm install @eternl/hub-core
```

也可以使用：`pnpm add @eternl/hub-core`、`yarn add @eternl/hub-core`、`bun add @eternl/hub-core`

## README

# @eternl/ hub- core

Eternl Hub SDKs的共享基础设施. 此套件提供了两者共同使用的基础 `@eternl/hub-dapp-sdk` 财务报告和审定财务报表 `@eternl/hub-wallet-sdk`:加密的传输,密码握手,有线协议,以及将它们联系在一起的对称会话层.

这是一个低级的软件包。 大多数应用代码应该使用角色特定的SDK(dApp / 钱包),而不是用手来给这些原始人接线. 原始人在此被记载为SDK作者和高级融合.

## 安装

```bash
npm install @eternl/hub-core
# or
pnpm add @eternl/hub-core
```

### 所需资源

-   运行时间与 **网络加密 API** (单位:千美元)`globalThis.crypto.subtle`: 浏览器,或 **节点.js 18**密码模块调用 `assertCryptoCapabilities()` 并抛出环境 没有它.
-   无害环境管理或CJS的消费者均得到支持(双管齐下) `import`编号 :`require` 以类型构建).

## 概览

这套材料分为以下几个领域:

-   **密码** - ECDH P-256钥匙交换+AES-256-GCM AEAD,带有PIN捆绑的密钥导出和用于MITM保护的6位短认证字符串(SAS6).
-   **会议** —— 说 `createPairSession`,拥有有线信封的对称协议层,加密/解密,心跳,出场乒乓球,并重放验证一对.
-   **运输** —— 说 `NatsTransport` (NATS WebSocket) 一个小后面 `Transport` 用于依赖性注入的界面。 A 类 `MockTransport` 测试双重机可从 `@eternl/hub-core/testing` 子路径.
-   **信件** ——打出的信息定义,类型守护,以及 `create…` dApp 钱包协议工厂.
-   **出席情况** ——为JetStream-stream-stream-base 存在协议的主体构建器,头键,和cadence常数.
-   **生命周期** —— 说 `LifecycleDispatcher`,一个单调,它将DOM/应用生命周期事件(tab隐藏/可见,页面隐藏/显示,应用背景/前方)向存在信标进行播放.
-   **类型 / Utils / 出错 / 常数** 共享类型Script类型、编码/事件帮助器、 `EternlConnectError` 类,和协议配置.

## 进口和子路径出口

生产原始从包根再出口:

```typescript
import { createSessionEncryption, createPairSession, NatsTransport } from '@eternl/hub-core';
```

每个地区也可作为进口较窄的次路径出口:

```typescript
import { createSessionEncryption } from '@eternl/hub-core/crypto';
import { EternlConnectError }      from '@eternl/hub-core/errors';
import { createApiCall }           from '@eternl/hub-core/messages';
import { createPairSession }       from '@eternl/hub-core/session';
import { NatsTransport }           from '@eternl/hub-core/transport';
import { LifecycleDispatcher }     from '@eternl/hub-core/lifecycle';
import { presencePublishSubject }  from '@eternl/hub-core/presence';
import type { AccountInfo }        from '@eternl/hub-core/types';
import { generateNonce }           from '@eternl/hub-core/utils';
```

有效的子路径是 `./crypto`, (中文(简体) ), `./errors`, (中文(简体) ), `./messages`, (中文(简体) ), `./session`, (中文(简体) ), `./presence`, (中文(简体) ), `./lifecycle`, (中文(简体) ), `./transport`, (中文(简体) ), `./types`,以及 `./utils`。 。 。 .

> 测试双等 `MockTransport` 活在奉献下 `@eternl/hub-core/testing` 子路径和故意 **没有** 生产根出口的一部分:
> 
> ```typescript
> import { MockTransport } from '@eternl/hub-core/testing';
> ```

## 密码

密码模块既暴露出低等原始人(`generateKeyPair`, (中文(简体) ), `deriveSharedSecret`, (中文(简体) ), `deriveSessionKey`, (中文(简体) ), `encrypt`, (中文(简体) ), `decrypt`, (中文(简体) ), `deriveSAS6`,.)和通过工厂创建的状态会话包装.

`SessionEncryption` 实值 **没有** 一个建筑师。 这是一个小物体暴露 `{ fromRaw }` (别名用于: `createSessionEncryptionFromRaw`) (中文(简体) ). 握手驱动的实例与 `createSessionEncryption(pairingId, pin)` 工厂:

```typescript
import { createSessionEncryption } from '@eternl/hub-core';
import { bytesToHex } from '@eternl/hub-core'; // also on '@eternl/hub-core/utils'

// Each side creates an encryption context bound to the shared pairingId + PIN.
const enc = createSessionEncryption(pairingId, pin);

// 1. Generate this side's ephemeral key pair; returns the raw public key bytes.
const myPublicKey = await enc.initialize();
const myPublicKeyHex = bytesToHex(myPublicKey); // send this to the peer
// (equivalently: enc.getPublicKeyHex())

// 2. After receiving the peer's public key (hex), complete the handshake.
//    completeHandshake takes a SINGLE argument: the peer public key as hex.
await enc.completeHandshake(peerPublicKeyHex);

// 3. Both sides display the 6-digit SAS for out-of-band confirmation.
const sas6 = enc.getSAS6(); // throws if called before completeHandshake

// 4. Encrypt. encrypt() returns { data, seq } — `seq` is a per-direction
//    monotonic counter that must travel alongside the ciphertext on the wire.
const { data, seq } = await enc.encrypt(new TextEncoder().encode('hello'));

// 5. The receiver decrypts using the same seq it read off the wire.
const plaintext = await enc.decrypt(data, seq);

// When finished, zero out the in-memory key material.
enc.dispose();
```

关键点(经核实与 `src/crypto/index.ts`:

-   `createSessionEncryption(pairingId, pin)` —— 说 `pin` 也许 `null` 只有在从持久性状态重建实例时(见下文); 新的握手需要非无核PIN.
-   `initialize()` 返回时 `Promise<Uint8Array>` (原始公用钥匙); `getPublicKeyHex()` 返回与十六进制相同的密钥.
-   `completeHandshake(peerPublicKeyHex)` 只能用一个理由.
-   `encrypt(plaintext)` 决定: `{ data: Uint8Array; seq: bigint }` 财务报告和审定财务报表 **需求** 握手完成; 称之为更早的掷出.
-   `decrypt(data, seq)` 要求 `seq` 是用密码传送的.
-   `getSAS6()` 掷出至 `completeHandshake` 已经运行.

### 从长期状态重建

在不重运行握手( 如重装后) 的情况下恢复加密上下文, 使用 `SessionEncryption.fromRaw` 编号 : `createSessionEncryptionFromRaw`数字 :

```typescript
import { SessionEncryption } from '@eternl/hub-core';

const enc = await SessionEncryption.fromRaw({
  pairingId,
  sessionKeyRaw, // 32-byte AES key
  pinAadBytes,   // PIN-hash AAD bytes captured during the original handshake
});
// `enc` can encrypt/decrypt immediately, but cannot run completeHandshake again.
```

## 会议

`createPairSession` 是对称协议层。 它是一个 `SessionEncryptionApi` 加一个 `Transport`,拥有有线信封(一个8字节的大-endian) `seq` aES-GCM blob 之后的前缀,在 `hub.pair.v2.<pairId>`,运行心跳,自动复制到存在 pings,并验证每个输入框上的回放/protocol-version.

```typescript
import {
  createSessionEncryption,
  createPairSession,
  NatsTransport,
} from '@eternl/hub-core';

const transport = new NatsTransport();
await transport.connect('wss://ws.hub.de-5.eternl.art'); // or DEFAULT_HUB_URL

const encryption = createSessionEncryption(pairId, pin);
await encryption.initialize();
// ... exchange public keys and call encryption.completeHandshake(peerPublicKeyHex) ...

const session = createPairSession({
  pairId,
  encryption,
  transport,
  enableHeartbeat: true, // default
});

// Listen for decrypted, validated inbound messages.
const off = session.on('message', ({ message, type }) => {
  // handle role-specific protocol messages (api-call/api-response, etc.)
});

// Send any protocol message object; it is stamped, encoded, encrypted, and published.
await session.send(someProtocolMessage);

// Active presence probe — resolves true if the peer pongs within the timeout.
const online = await session.requestPresenceCheck();

// Cleanup (also available via `using` / Symbol.dispose).
off();
session.dispose();
```

`createPairSession` 也发出命名事件,用于可观察性和生命周期反应: `presencePing`, (中文(简体) ), `presencePong`, (中文(简体) ), `heartbeatReceived`, (中文(简体) ), `peerPresence`, (中文(简体) ), `peerDisconnect`, (中文(简体) ), `peerPairingRemoved`,以及 `error`。角色层( dApp 和钱包 SDKs) `'message'` 活动.

## 运输

```typescript
import { NatsTransport } from '@eternl/hub-core';

const transport = new NatsTransport();
await transport.connect('wss://ws.hub.de-5.eternl.art'); // or DEFAULT_HUB_URL

const sub = transport.subscribe('hub.pair.v2.<pairId>', (data) => {
  // data is a Uint8Array
});

await transport.publish('hub.pair.v2.<pairId>', encodedBytes);

sub.unsubscribe();
await transport.disconnect();
```

`connect(url, opts?)` 接受每个连接的验证器。 针对生产超级集群(默认的ACLs),你必须提供一种——要么是静态的 `authenticator` 或,对于长期会期,a `getAuthenticator` 提供商在每次重联时重命名证书. `MockTransport` (进口自 `@eternl/hub-core/testing`) 执行相同的 `Transport` 用于测试和记录的界面 `publishedMessages`。 。 。 .

## 信件

```typescript
import {
  MessageType,
  createApiCall,
  isApiResponse,
  encodeMessage,
  decodeMessage,
  generateNonce,
} from '@eternl/hub-core';

const decoded = decodeMessage(bytes);
if (isApiResponse(decoded)) {
  // handle the response
}
```

模块导出已键入信件界面 `MessageType` 数值映射, `is…` 类型警卫,和 `create…` 工厂`createConnectRequest`, (中文(简体) ), `createApiCall`, (中文(简体) ), `createHeartbeat`, (中文(简体) ), `createPresencePing`(见A/C.5/49/70,附件)。 这个 `create…` 工厂使用非ce生成器;在本包中,非ce由 `generateNonce(sessionId)`。 。 。 .

| 信件类型 | 说明 |
| --- | --- |
| `CONNECT_REQUEST` 编号 : `CONNECT_RESPONSE` | DAPP 请求连接; 钱包批准/ 拒绝 |
| `API_CALL` 编号 : `API_RESPONSE` | DAPP 调用 CIP- 30/ CIP- 95 方法; 钱包返回结果 |
| `ACCESS_GRANTED` 编号 : `ACCESS_DENIED` | 按要求作出的访问决定 |
| `ACCOUNT_SWITCH` 编号 : `ACCOUNT_CHANGED` | 更改账户请求/通知 |
| `DISCONNECT` 编号 : `PAIRING_REMOVED` | 临时断开/ 永久断开 |
| `HEARTBEAT` | 保持存活状态 |
| `PRESENCE` 编号 : `PRESENCE_PING` 编号 : `PRESENCE_PONG` | 存在状态和往返探测 |

## 类型

```typescript
import type { AccountInfo, NetworkType } from '@eternl/hub-core';
import { Permission } from '@eternl/hub-core';

const network: NetworkType = 'mainnet';

const permissions = [
  Permission.ADDRESS_READ, // 'address_read'
  Permission.SIGN_TX,      // 'sign_tx'
];
```

`Permission` 包括CIP-30核心方法(`NETWORK_ID`, (中文(简体) ), `ADDRESS_READ`, (中文(简体) ), `SIGN_TX`, (中文(简体) ), `SUBMIT_TX`(......)和CIP-95治理(`GOVERNANCE`, (中文(简体) ), `DREP_KEY`, (中文(简体) ), `STAKE_KEYS`) (中文(简体) ).

## 错误

```typescript
import { EternlConnectError, ErrorCode } from '@eternl/hub-core';

try {
  // ... operation
} catch (error) {
  if (error instanceof EternlConnectError) {
    console.log(error.code);        // ErrorCode enum value
    console.log(error.recoverable); // boolean — whether a retry may succeed
    console.log(error.cause);       // original error, if wrapping one
  }
}
```

`EternlConnectError` 是整个软件包中使用的单一错误类型。 它携带一个 `ErrorCode` (例如:. `TIMEOUT`, (中文(简体) ), `DECRYPTION_FAILED`, (中文(简体) ), `REPLAY_DETECTED`, (中文(简体) ), `HUB_UNAVAILABLE`页:1 `recoverable` 旗帜和可选 `cause`静态帮助者(`EternlConnectError.timeout`, (中文(简体) ), `.decryptionFailed`, (中文(简体) ), `.replayDetected`,.)构建常见案例.

## 常数

```typescript
import {
  PROTOCOL_VERSION,
  DEFAULT_HUB_URL,
  SESSION_EXPIRY_MS,
  RECONNECTION,
  NONCE_WINDOW_MS,
  CHANNELS, // CHANNELS.PAIR_V2(pairId) === `hub.pair.v2.${pairId}`
} from '@eternl/hub-core';
```

`DEFAULT_HUB_URL` 是 Eternl 参考 NATS WebSocket 端点, 目前 `wss://ws.hub.de-5.eternl.art`。通过将不同的 URL 传递到 `transport.connect(url)`。 。 。 .

## 安保模式

包裹的中央安全财产是 **耐MITM配对** 在两个设备之间共享一个简短的PIN。 设计(见 `src/crypto/index.ts`将四种机制结合起来:

1.  **ECDH P-256 + AES-256-GCM. 欧洲人大常委会.** 每方生成一对电平钥匙,交换公用钥匙,并通过ECDH获得共同的秘密. 框架由AES-256-GCM(认证加密)封存.
    
2.  **PIN 键导出 .** 会话密钥是 `HKDF-SHA256(sharedSecret, salt = SHA-256(utf8(pin) || pairingId), info = "eternl-hub-v2")`。 。 。 . 将盐装入PIN意味着攻击者可以代替公用钥匙,但确实 **没有** 了解PIN不能获得相同的会话密钥,即使完全了解他们谈判的共同秘密.
    
3.  **SAS6( Short 认证字符串).** 6位数的代码来源于共享密语 + PIN 绑定的盐 在一个独特的 HKDF 下 `info` 标签。 双同位素显示,用户确认匹配出带. 如果一个MITM替换出一个或两个公用密钥,那么每一边都会得到不同的共享密钥,所以两个SAS6代码存在分歧,用户在任何签名流量流之前都会中止.
    
4.  **每帧 AAD + 重放/非保护.** 每个 AEAD 框架的额外认证数据是 `utf8(pairingId) || SHA-256(pin)[:8] || be64(seq)`。使用不同的 PIN 或配对Id 的对等点会在每个框架上失败 AES-GCM 认证。 滑动窗口非ce验证符( E)`createNonceValidator`窗口 = `NONCE_WINDOW_MS`拒绝重复播放或陈旧的电文,以及 `createPairSession` 拒绝协议版本不匹配的帧 `PROTOCOL_VERSION`。 。 。 .
    

`seq` aAD和电线信封中都装着一个每个方向的单调计数器。 注意严格 **命令执行被推迟到 SDK 层** —— 说 `hub-core` 验证非ce窗口和 AAD `seq` 匹配密码文本,但本身并不拒绝超出再播放检测的订单外发送.

## 许可证

商业来源许可证1.1(`BUSL-1.1`) (中文(简体) ). 见 [自由主义](https://npmcn.com/package/%40eternl/hub-core/LICENSE)。 。 。 .

许可是Tastenkunst GmbH。 额外使用赠款 : `None` - 你可以复制、修改和制作 **非生产** 使用此软件包。 生产/商业用途需要从塔斯滕昆斯特获得单独的许可证。 在"更改日期"(每个版本首次出版的四周年)上,该版本会转换为GPL-2.0-或-后期.

联系人 : [https://tastenkunst.com/ (中文(简体) )](https://tastenkunst.com/)

## 常见问题

### @eternl/hub-core 是什么？

Eternl Hub SDKs的共享基础设施\.

### 如何安装 @eternl/hub-core？

在项目目录运行 npm install @eternl/hub-core，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：@nats-io/nats-core（3\.4\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @eternl/hub-core 支持 TypeScript 吗？

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

### @eternl/hub-core 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @eternl/hub-core 可以商用吗？

@eternl/hub-core 使用 BUSL-1\.1 许可。声明的许可为 BUSL-1\.1，请阅读许可原文确认使用条件。以上为概括，不构成法律意见，请以许可原文为准。

### @eternl/hub-core 的下载量有多少？

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

### @eternl/hub-core 还在维护吗？

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

