# 402-announce 中文文档

规范地址：https://npmcn.com/package/402-announce/

版本：2\.3\.1
npm 元数据更新时间：2026-10-18T15:59:23.305Z
中文译文更新时间：2026-11-07T03:43:13.548Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/402-announce
原文对照：https://npmcn.com/package/402-announce/?lang=original
项目主页：https://402.pub/
源码仓库：https://github.com/forgesworn/402-announce

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

- 包体积（解压后）：268 kB，49 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=18
- 运行依赖：2 个
- 首次发布：2026-03-14T20:57:56.554Z
- 最新版本发布：2026-10-18T15:59:23.016Z
- 近 30 天下载量：2063（2026-10-04 至 2026-11-02，npm 官方下载统计）
- 已发布版本数：29（近 12 个月 29 个）

## 中文简介

在Nostr上公布HTTP 402服务(L402和x402),用于分权发现. Kind 31402参数化可替换事件.

## 安装

```sh
npm install 402-announce
```

也可以使用：`pnpm add 402-announce`、`yarn add 402-announce`、`bun add 402-announce`

## README

# 402发通知

实验存储发现 现在有一个单独的,没有钥匙的API 对于公众付费 包和免费镜像掩蔽。 见 [第1版合同](https://npmcn.com/package/402-announce/docs/storage-service-v1.md), (中文(简体) ), [杰森·斯克马](https://npmcn.com/package/402-announce/schemas/storage-service-v1.schema.json) 财务报告和审定财务报表 [已签名的互操作性固定装置](https://npmcn.com/package/402-announce/fixtures/storage-v1/manifest.json)。 。 。 . `buildStorageAnnouncement` 为外部签名者创建未签名的事件; `acceptSignedStorageAnnouncement` 核实准确的返回事件 `selectStorageAnnouncements` 保存已过期/已撤销的替换记录. 这些API不发布,联系存储节点或购买存储. 现有 已支付 API `announceService` 合同不变.

**诺斯特:** [`npub1mgvlrnf5hm9yf0n5mf9nqmvarhvxkc6remu5ec3vf8r0txqkuk7su0e7q2`](https://njump.me/npub1mgvlrnf5hm9yf0n5mf9nqmvarhvxkc6remu5ec3vf8r0txqkuk7su0e7q2)

在Nostr上宣布HTTP 402服务 用于分散的发现. 支持L402和x402支付协议.

[![CI](https://github.com/forgesworn/402-announce/actions/workflows/ci.yml/badge.svg)](https://github.com/forgesworn/402-announce/actions/workflows/ci.yml) [![Coverage](https://img.shields.io/badge/coverage-95%25-brightgreen.svg)](https://npmcn.com/package/402-announce/README.md) [![MIT Licence](https://img.shields.io/badge/licence-MIT-blue.svg)](https://npmcn.com/package/402-announce/LICENSE) [![GitHub Sponsors](https://img.shields.io/github/sponsors/TheCryptoDonkey?logo=githubsponsors&color=ea4aaa&label=Sponsor)](https://github.com/sponsors/TheCryptoDonkey)

出版物 **类型31402** 参数化可替换的事件,以便AI代理(和任何诺斯特客户端)可以在没有中央注册的情况下发现付费API.

**[活盘](https://402.pub/)** 立刻在网络上公布.

## 如何运作

```mermaid
flowchart LR
    A[Your API] -->|"npm install<br/>402-announce"| B[402-announce]
    B -->|"kind 31402<br/>signed event"| C[(Nostr Relays)]
    C -->|subscribe & filter| D[402-mcp]
    D -->|discover + pay| A

    style B fill:#f59e0b,color:#000
    style C fill:#8b5cf6,color:#fff
    style D fill:#3b82f6,color:#fff
```

您的API 向 Nostr 中继器发布服务公告 。 人工智能特工(通过 [402-mcp (中文(简体) )](https://github.com/forgesworn/402-mcp)发现后支付发票,消费API. 无需中央登记处.

## 快开始

```bash
npm install 402-announce
```

402 通知只是无害环境管理。 它的船没有共同JS的建造及其 `exports` 地图没有 `require` 条件,所以 `require('402-announce')` 失败 `ERR_PACKAGE_PATH_NOT_EXPORTED`启用 `import`,或 `await import('402-announce')` 从普通JS.

```typescript
import { announceService } from '402-announce'

const handle = await announceService({
  secretKey: '64-char-hex-nostr-secret-key',
  relays: ['wss://relay.damus.io', 'wss://relay.primal.net'],
  identifier: 'jokes-api',
  name: 'Jokes API',
  urls: ['https://jokes.example.com'],
  about: 'A joke-telling service behind an L402 paywall',
  pricing: [
    { capability: 'get_joke', price: 1, currency: 'sats' },
  ],
  paymentMethods: [['l402', 'lightning'], ['cashu'], ['xcashu']],
  topics: ['comedy', 'ai'],
  capabilities: [
    { name: 'get_joke', description: 'Returns a random joke' },
  ],
  version: '1.0.0',
})

console.log('Published event:', handle.eventId)
console.log('From pubkey:', handle.pubkey)

// Later, when shutting down:
handle.close()
```

**多种运输实例** (清网+Tor + 握手-相同服务,不同接入路径):

```typescript
const handle = await announceService({
  secretKey: '64-char-hex-nostr-secret-key',
  relays: ['wss://relay.damus.io', 'wss://relay.primal.net'],
  identifier: 'jokes-api',
  name: 'Jokes API',
  urls: [
    'https://jokes.example.com',                  // clearnet
    'http://jokesxyz...onion',                    // Tor hidden service
    'https://jokes.example.hns',                  // Handshake domain
  ],
  about: 'A joke-telling service behind an L402 paywall',
  pricing: [{ capability: 'get_joke', price: 1, currency: 'sats' }],
  paymentMethods: [['l402', 'lightning']],
  topics: ['comedy', 'ai'],
})
```

每个 URL 成为单独的 `url` 标记于 31402 类事件。 客户端按顺序尝试,并使用可以达到的任意方法.

`urls` 接受1至10个条目。 并不是每个可解析的 URL 被接受: 见 [URL和中继验证](https://npmcn.com/package/402-announce/#readme-url-and-relay-validation)。 。 。 .

见 [`examples/`](https://github.com/forgesworn/402-announce/tree/main/examples) gitHub 仓库中可运行脚本的目录。 它不包含在 npm 包中 .

## 如何融为一体

```mermaid
flowchart LR
    subgraph "Your Server"
        API[Your API]
        TB[toll-booth<br/>L402 paywall]
        AN[402-announce]
    end

    subgraph "Nostr Network"
        R1[(Relay 1)]
        R2[(Relay 2)]
    end

    subgraph "AI Agent"
        MCP[402-mcp<br/>discovery + payment]
    end

    API --> TB
    TB -->|"protects"| API
    AN -->|"kind 31402"| R1
    AN -->|"kind 31402"| R2
    R1 -->|"subscribe"| MCP
    R2 -->|"subscribe"| MCP
    MCP -->|"HTTP + L402 token"| TB

    style TB fill:#ef4444,color:#fff
    style AN fill:#f59e0b,color:#000
    style MCP fill:#3b82f6,color:#fff
```

1.  **[收费](https://github.com/forgesworn/toll-booth)** 用 L402 付费墙包裹您的 API
2.  **402发通知** 发布描述服务、定价和支付方法的31402类事件
3.  **[402-mcp (中文(简体) )](https://github.com/forgesworn/402-mcp)** 发现通知,支付发票,并拨打你的API

## 它会做什么

-   构建和标志 31402 诺斯特事件
-   以平行方式发布给一个或多个 Nostr 中继器
-   使用后 Zeroise 密钥字节
-   当单个接力失败时(如果每次接力失败,仍能解决;见 [`announceService`](https://npmcn.com/package/402-announce/#readme-announceserviceconfig-promiseannouncement)(中文(简体) )
-   规定 a `close()` 干净断开的控件

## 它不会做的

-   不运行 L402 付费墙( 使用) [收费](https://github.com/forgesworn/toll-booth) 为此)
-   不订阅或搜索通知(使用 [402-mcp (中文(简体) )](https://github.com/forgesworn/402-mcp) 为此)
-   不处理付款或符号核查

## API 密码

### `announceService(config): Promise<Announcement>`

高级功能,用于构建,签名,并发布事件给多个中继器.

**回返** a 一个 `Announcement` 控件 :

-   `eventId`: 已签名的诺斯特事件的ID
-   `pubkey`: 从您的密钥中衍生出来的诺斯特公钥
-   `close()`: 断开所有中继器( 同步; 在关闭时调用, 以避免泄露 WebSockets)

**拒绝** (这是一个 `async` 当配置无效时: a `secretKey` 这不是64个十六进制字符, 一个空接力列表, 超过50个接力, 一个不是的接力 URL `ws://` 或者说 `wss://`,在私人或回放主机、服务中拥有证书或分数 `urls` 列表中没有公共 URL,或者任何 `buildAnnounceEvent` 验证失败.

**中继失败永远不会拒绝.** 每个中继器都与10秒的连接超时同时进行试验,并记录故障 `console.warn`如果每次中继失败, `announceService` 仍然决定与 `eventId` 和日志 `[402-announce] No relays accepted the event`编辑 `Announcement` handle不报告有多少继电器接受事件,所以警告是唯一的信号. 如果您需要知道至少一个中继存储了事件,请拨 `buildAnnounceEvent` 然后自己出版,检查每个 `relay.publish()` 结果.

### `buildAnnounceEvent(secretKey, config): VerifiedEvent`

下层功能,用于构建和签名事件而不发布. 如果你自己管理中继连接,那就有用了. `config` 是一个 `AnnounceConfig` 无 `relays`。它会同步投放无效输入,不应用“至少一个公共URL”规则.

### `isPrivateHost(hostname): boolean`

SSRF负责保护 `announceService` 适用于转发和服务 URL,导出为您自己使用。 它需要一个赤裸的主机名( 不是 URL) 然后返回 `true` 用于:

-   `localhost`, (中文(简体) ), `*.localhost`
-   IPv6 请检查url=值 (帮助) `::1`, (中文(简体) ), `::`链接 - 本地 `fe80::/10`,独特的本地 `fc00::/7`,泰雷多语 `2001:0000::/32`,和 IPv4-映射, IPv4-相容或 6to4 形式嵌入私人 IPv4 地址
-   IPv4 请检查url=值 (帮助) `0.0.0.0/8`, (中文(简体) ), `10.0.0.0/8`, (中文(简体) ), `100.64.0.0/10`, (中文(简体) ), `127.0.0.0/8`, (中文(简体) ), `169.254.0.0/16`, (中文(简体) ), `172.16.0.0/12`, (中文(简体) ), `192.0.0.0/24`, (中文(简体) ), `192.0.2.0/24`, (中文(简体) ), `192.88.99.0/24`, (中文(简体) ), `192.168.0.0/16`, (中文(简体) ), `198.18.0.0/15`, (中文(简体) ), `198.51.100.0/24`, (中文(简体) ), `203.0.113.0/24` 财务报告和审定财务报表 `240.0.0.0/4`
-   八进制,十六进制,单整数和两相或三相接的接头IPv4拼写法(例如: `0x7f000001`, (中文(简体) ), `2130706433`, (中文(简体) ), `127.1`(中文(简体) )

它只检查字符串,从来不解决DNS. 它不标出多播地址, 例如 : `224.0.0.1`。 。 。 .

### 常数和类型

-   `L402_ANNOUNCE_KIND`:事件的类型, `31402`
-   `AnnounceConfig`, (中文(简体) ), `Announcement`, (中文(简体) ), `PricingDef`, (中文(简体) ), `CapabilityDef`: 纯类型导出

```typescript
interface PricingDef {
  capability: string // 1-64 characters, no control characters
  price: number      // finite and non-negative
  currency: string   // any non-blank string up to 32 characters, no control characters
}

interface CapabilityDef {
  name: string         // up to 128 characters
  description: string  // up to 4096 characters
  endpoint?: string    // starts with '/', 'http://' or 'https://'; up to 2048 characters
  schema?: unknown     // JSON Schema for the input
  outputSchema?: unknown // JSON Schema for the output
}
```

`currency` 是一个自由形式的标签,而不是一个引用: 库不对照允许的值列表来检查,以及 `'sats'` 仅是整个文档中使用的价值。 客户是否理解另一个单位,取决于该客户. `pricing` 需要1至100个条目和 `capabilities` 最多100个。 整个事件内容可能达到最多64个KiB和20个等级的筑巢.

### 配置选项

| 外地 | 类型 | 需求 | 说明 |
| --- | --- | --- | --- |
| `secretKey` | `string` | 对 | 64 Char 十六进制鼻音密钥 |
| `relays` | `string[]` | 对 | 中继 URL (E)`wss://` 或者说 `ws://`(中文(简体) ) |
| `identifier` | `string` | 对 | 独一无二的上市ID( Nostr) `d` 标签) |
| `name` | `string` | 对 | 可读服务名称 |
| `urls` | `string[]` | 对 | 服务运输端点(1-10个独特的条目,每个条目最多可达2048个字符;一些方案被拒绝 `announceService` 需要一个公开的 URL,参见 [URL和中继验证](https://npmcn.com/package/402-announce/#readme-url-and-relay-validation)(中文(简体) ) |
| `about` | `string` | 对 | 简短说明 |
| `pricing` | `PricingDef[]` | 对 | 个人能力定价 |
| `paymentMethods` | `string[][]` | 对 | 接受付款方法(每个条目为: `[rail, ...params]`(中文(简体) ) |
| `picture` | `string` | 没有 | 图标 URL |
| `topics` | `string[]` | 没有 | 过滤的主题标签 |
| `capabilities` | `CapabilityDef[]` | 没有 | 能力细节(存储于事件内容) |
| `version` | `string` | 没有 | 服务版本( 存储于事件内容) |

### URL和中继验证

两者 `buildAnnounceEvent` 财务报告和审定财务报表 `announceService` 拒绝一个 `urls` 条目:

-   无法解析 `new URL()`,大于2048个字符或包含控件字符
-   使用此方案 `data:`, (中文(简体) ), `file:`, (中文(简体) ), `javascript:`, (中文(简体) ), `blob:` 或者说 `vbscript:`
-   复制另一个条目

`buildAnnounceEvent` 停止那里并接受私人主机,因为它只是串行. `announceService` 还需要至少一个公共 URL: a `http:` 或者说 `https:` 主机名的 URL `isPrivateHost` 不符, a `.onion` 主机名,或任何其他方案(后两个跳过主机检查). 其余的条目可能是私人的.

中继 URL 更为严格 : `ws://` 或者说 `wss://` 只有,没有嵌入式证书,没有私有或回回机主机,最多在去除后50个. A 类 `ws://` 中继记录一个警告.

这些检查只读取主机名文本 。 没有DNS分辨率,因此DNS重新绑定没有被捕获;部署在网络层的Egress控制后.

## 存储通知 API

此 README 顶部描述的存储扩展是无密钥的: 它构建未签名的事件, 验证外部签名器返回的事件, 并在它们之间选择 。 它不发布、联系存储节点或购买存储,而是与 `announceService`。不要将存储描述传递给 `announceService` 或者说 `buildAnnounceEvent`。 。 。 .

导入路径 。 这6个功能从 `402-announce/storage` 子路径, 也来自套件根 :

```typescript
import { buildStorageAnnouncement } from '402-announce/storage'
// or: import { buildStorageAnnouncement } from '402-announce'
```

子路径只包含六个功能和 `ParsedStorageAnnouncement` 类型。 常数( E) :`STORAGE_PROFILE`, (中文(简体) ), `STORAGE_SERVICE_PATH`, (中文(简体) ), `STORAGE_MAX_EVENT_BYTES`, (中文(简体) ), `STORAGE_MAX_TTL_SECONDS`, (中文(简体) ), `STORAGE_DEFAULT_MAX_AGE_SECONDS`说明类型(例如: `StorageServiceDescription` 财务报告和审定财务报表 `StorageReadOptions`)只从根导出.

| 函数 | 签署 | 目的 |
| --- | --- | --- |
| `buildStorageAnnouncement` | `(value: unknown, createdAt?: number) => EventTemplate` | 验证一个描述并返回一个外部签名符的未签名的 31402 事件 |
| `acceptSignedStorageAnnouncement` | `(value: unknown, requested: EventTemplate, options: StorageReadOptions) => ParsedStorageAnnouncement` | 校验返回的事件, 并且只有在它与当前事件相同时才接受它 `requested` (同样善良, `created_at`,标签和内容) |
| `parseStorageAnnouncement` | `(value: unknown, options: StorageReadOptions) => ParsedStorageAnnouncement` | 校验一个签名的事件, 并返回其中的描述和 a `freshness` 联 合 国 `'current'`, (中文(简体) ), `'stale'` 或者说 `'expired'` |
| `selectStorageAnnouncements` | `(values: readonly unknown[], options: StorageReadOptions) => ParsedStorageAnnouncement[]` | 保持每个小酒鬼最新的有效记录 `d` 标记,包括已过期和已撤回的;无效的记录被跳过 |
| `validateStorageDescription` | `(value: unknown) => StorageServiceDescription` | 严格验证和复制一个公开的 HTTP 描述 |
| `validateStorageEndpointBinding` | `(value: unknown, announcement: ParsedStorageAnnouncement, selectedOrigin: string, options: StorageReadOptions) => StorageServiceDescription` | 对照签名的身份、列名和选定来源检查新获取的描述 |

`StorageReadOptions` 实值 `{ now: number; maxAgeSeconds?: number; clockSkewSeconds?: number }`,与 `now` 在Unix秒内。 函数抛出 `Error('Invalid storage service profile.')` 输入无效. `selectStorageAnnouncements` 跳过无效的记录取而代之,但仍为无效选项丢出或超过512个记录.

流量为构建,对外签名,接受,选择,再绑定到终点. 下面的例子使用一个丢弃的本地密钥作为外部签名器的站口(`nostr-tools` 是此软件包的依赖性 。 在生产中,密钥从未输入此代码 .

```typescript
import { finalizeEvent, generateSecretKey, getPublicKey } from 'nostr-tools/pure'
import {
  acceptSignedStorageAnnouncement,
  buildStorageAnnouncement,
  selectStorageAnnouncements,
  validateStorageEndpointBinding,
} from '402-announce/storage'

const now = Math.floor(Date.now() / 1000)
const signerKey = generateSecretKey() // stand-in for an external signer

const description = {
  profile: 'forgesworn-storage-service-v1',
  service_pubkey: getPublicKey(signerKey),
  identifier: 'open-shelter-node',
  name: 'Open shelter node',
  about: 'Best-effort mirror shelter for signed blobs.',
  origins: ['https://storage.example/'],
  max_blob_bytes: 1073741824,
  observed_at: now,
  expires_at: now + 7200,
  state: 'published',
  checkout: null,
  services: [{
    id: 'open-shelter',
    type: 'free-mirror',
    revision: 1,
    availability: 'accepting',
    operation: 'mirror',
    authorisation: 'bud-11',
    retention: 'best-effort',
    eviction_policy: 'Guest mirrors can be evicted under storage pressure.',
  }],
}

// 1. Build the unsigned event. No key or network access.
const requested = buildStorageAnnouncement(description)

// 2. Sign it externally. The signer must not change the template.
const signed = finalizeEvent(requested, signerKey)

// 3. Accept the returned event. Throws if the signature, freshness or template differ.
const accepted = acceptSignedStorageAnnouncement(signed, requested, { now })
// Publishing accepted.event to relays is a separate step that you perform.

// 4. Later, a reader selects the newest record per listing from relay results.
const listings = selectStorageAnnouncements([accepted.event], { now })
const [listing] = listings
// Keep `listings` as watermarks. Show only current, published, accepting services.

// 5. After separately fetching the node's description (GET /services/v1, here reusing
//    `description`), check it matches the signed listing and the chosen origin.
const fetched = description
const current = validateStorageEndpointBinding(fetched, listing, 'https://storage.example/', { now })
console.log(current.identifier)
```

支付存储列表 `checkout` 对象和 `paid-storage` 服务。 见 [第1版合同](https://npmcn.com/package/402-announce/docs/storage-service-v1.md) 每个字段和 [签名固定装置](https://npmcn.com/package/402-announce/fixtures/storage-v1/manifest.json) 已支付、合并、撤回和过期的例子.

## 宣布流量

```mermaid
flowchart TD
    A[announceService config] --> B{Validate}
    B -->|"secretKey: 64-char hex"| C[Derive pubkey]
    B -->|"relays: wss:// URLs"| C
    C --> D[Build kind 31402 event]
    D --> E[Sign with secret key]
    E --> F[Zeroise key bytes]
    F --> G["Connect relays (parallel, 10s timeout)"]
    G --> H{Each relay}
    H -->|success| I[Publish event]
    H -->|failure| J[Log warning, continue]
    I --> K["Return { eventId, pubkey, close() }"]
    J --> K
```

## 事件格式

每个通知都是 **类型31402** 参数化可替换事件。 组合 `pubkey` + 键 `d` 标记独有地识别列表——再次以相同值发布更新了现有的列表.

```mermaid
graph TB
    subgraph "Kind 31402 Event"
        direction TB
        subgraph Tags
            D["d: jokes-api"]
            N["name: Jokes API"]
            U1["url: https://jokes.example.com"]
            U2["url: https://jokesapi.example.onion (optional)"]
            AB["about: A joke-telling service"]
            PMI1["pmi: l402, lightning"]
            PMI2["pmi: cashu"]
            P["price: get_joke, 1, sats"]
            T["t: comedy"]
        end
        subgraph Content["Content (JSON)"]
            CAP["capabilities: [{ name, description }]"]
            VER["version: 1.0.0"]
        end
    end

    style Tags fill:#1e293b,color:#e2e8f0
    style Content fill:#1e293b,color:#e2e8f0
```

### 标记

| 标记 | 需求 | 说明 | 示例 |
| --- | --- | --- | --- |
| `d` | 对 | 此列表的独特标识符 | `jokes-api` |
| `name` | 对 | 可读服务名称 | `Jokes API` |
| `url` | 对 | HTTP 端点( 每个 URL 一个标签; 可重复) | `https://jokes.example.com` |
| `about` | 对 | 简短说明 | `A joke-telling service` |
| `pmi` | 对 | 支付方法标识符(可重复、多要素) | `l402`, (中文(简体) ), `lightning` |
| `price` | 对 | 能力定价(可重复) | `get_joke`, (中文(简体) ), `1`, (中文(简体) ), `sats` |
| `t` | 没有 | 搜索/过滤的主题标签( 可重复) | `comedy` |
| `picture` | 没有 | 图标 URL | `https://example.com/icon.png` |

### 公认付款方法铁路

每个 `paymentMethods` 条目是第一个元素是铁路标识符,随后的元素是铁路专用参数的数组.

| 铁路 | 示例 | 说明 |
| --- | --- | --- |
| `l402` | `['l402', 'lightning']` | L402协议(照明BOLT-11发票) |
| `cashu` | `['cashu']` | 现金(普通) |
| `xcashu` | `['xcashu']` | Cashu 电子现金通过 NUT-24(X-Cashu 头) |
| `lnurlcash` | `['lnurlcash', 'mint.example']` | 在X-LNURLCASH标题中呈现的LUD-25无记名纸条(随后的元素是被接受的薄荷主机) |
| `x402` | `['x402', 'base', 'usdc', '0xabc...']` | x402 稳定币付款( 链、 令牌、 接收地址) |
| `payment` | `['payment', 'lightning']` | IETF 支付协议 |

### 内容

事件内容是一个带有可选字段的JSON对象. 每种能力也可携带 `endpoint`, (中文(简体) ), `schema` 财务报告和审定财务报表 `outputSchema` (见 `CapabilityDef` 上文:

```json
{
  "capabilities": [
    { "name": "get_joke", "description": "Returns a random joke", "endpoint": "/api/joke" }
  ],
  "version": "1.0.0"
}
```

## 多个 URL 对多个事件

这种区分对操作者很重要:

**一次事件的多个 URL** ——使用 `urls: ['...', '...']` 当 URL 代表 **同一服务** 不同运输方式(清网、Tor、握手)。 定价、证书和马卡龙签名密钥相同。 客户端选择可以达到的URL 。 这是为了抵制审查 和冗余.

**单独的31402事件** ——发布新活动(不同) `identifier`当你有 **真正不同的服务**:每辆运输不同的定价等级,不同的能力,或独立运营的服务. 单一事件应描述一种逻辑服务.

简而言之:同一服务+不同的网络路径 + 一个有多个事件 `url` 标签。 不同的服务——单独的活动.

## 警卫

-   密钥字节在签名后立即被零化( 在两个字节中) `announceService` 财务报告和审定财务报表 `buildAnnounceEvent`(中文(简体) )
-   永远不要登录或坚持秘密密钥——让图书馆处理清理
-   中继连接使用10秒超时防止挂起
-   单个接力故障被记录为警告,但不要拒绝承诺. 如果每一个中继失败, `announceService` 仍然决定与 `eventId` 和日志 `[402-announce] No relays accepted the event`
-   以私有模式和回回模式检查中继和服务 URL(见 [URL和中继验证](https://npmcn.com/package/402-announce/#readme-url-and-relay-validation)); DNS 重新绑定没有被捕获

## 生态系统

| 软件包 | 目的 |
| --- | --- |
| [收费](https://github.com/forgesworn/toll-booth) | L402 中间软件——任何API在几分钟内成为收费站 |
| [罚单](https://github.com/forgesworn/toll-booth-announce) | Bridge – 宣布一个功能呼叫的收费站服务 |
| [配置门](https://github.com/forgesworn/satsgate) | 提供闪电和Cashu支助的生产L402网关 |
| [402-mcp (中文(简体) )](https://github.com/forgesworn/402-mcp) | MCP 服务器,供 AI 代理商发现、支付和消费 402 API |
| [活盘](https://402.pub/) | 查看网络上宣布的每个服务 |

## ForgeSworn 工具包的一部分

[福吉斯沃恩语Name](https://forgesworn.dev/) 为诺斯特建立开源加密身份,支付和协调工具.

| 图书馆 | 它会做什么 |
| --- | --- |
| [树](https://github.com/forgesworn/nsec-tree) | 决定性的子标识衍生 |
| [环西格](https://github.com/forgesworn/ring-sig) | 秒数256k1上的 SAG/LSAG 环签名 |
| [区域防护](https://github.com/forgesworn/range-proof) | 佩德森承诺范围证明 |
| [金丝雀](https://github.com/forgesworn/canary-kit) | 胁迫性口语核查 |
| [手语](https://github.com/forgesworn/spoken-token) | 人称核查标志 |
| [收费](https://github.com/forgesworn/toll-booth) | L402 支付中间软件 |
| [土拨鼠](https://github.com/forgesworn/geohash-kit) | 覆盖多边形的Geohash工具包 |
| [节点证明](https://github.com/forgesworn/nostr-attestations) | NIP-VA可核查的证明 |
| [统治权](https://github.com/forgesworn/dominion) | 基于 Epoch 的加密访问控制 |
| [鼻孔微风](https://github.com/forgesworn/nostr-veil) | 隐私保护信任网 |

## 许可证

[麻省理工学院](https://npmcn.com/package/402-announce/LICENSE)

## 常见问题

### 402-announce 是什么？

在Nostr上公布HTTP 402服务\(L402和x402\),用于分权发现\. Kind 31402参数化可替换事件\.

### 如何安装 402-announce？

在项目目录运行 npm install 402-announce，或使用 pnpm add / yarn add / bun add。

### 402-announce 支持 TypeScript 吗？

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

### 402-announce 支持 ESM 还是 CommonJS？

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

### 402-announce 需要什么版本的 Node\.js？

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

### 402-announce 可以商用吗？

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

### 402-announce 的下载量有多少？

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

### 402-announce 还在维护吗？

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

