# @gusnips/one-click-dns 中文文档

规范地址：https://npmcn.com/package/%40gusnips/one-click-dns/

版本：0\.1\.5
npm 元数据更新时间：2026-11-01T06:01:06.748Z
中文译文更新时间：2026-11-01T07:15:49.332Z
软件包许可：MIT

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

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

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

- 包体积（解压后）：204 kB，22 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=20
- 运行依赖：0 个
- peer 依赖：@gusnips/server \>=0\.14\.3
- 首次发布：2026-10-29T10:47:47.874Z
- 最新版本发布：2026-11-01T06:01:06.562Z
- 已发布版本数：7（近 12 个月 7 个）

## 中文简介

将DNS记录放在客户的区域中：找到他们的DNS主机，将它们发送到签名的Domain Connect链接，使用API令牌编写，或显示该主机的步骤

## 安装

```sh
npm install @gusnips/one-click-dns
```

也可以使用：`pnpm add @gusnips/one-click-dns`、`yarn add @gusnips/one-click-dns`、`bun add @gusnips/one-click-dns`

## README

# @gusnips / one-click-dns

将DNS记录放在客户的区域中。该包找到它们的DNS所在的位置，然后为您提供添加记录的最佳方式：签名的Domain Connect链接、粘贴的API令牌或该主机的步骤。

```bash
npm install @gusnips/one-click-dns
# or
bun add @gusnips/one-click-dns
```

它有三个切入点：

-   `@gusnips/one-click-dns`：在浏览器中运行。主机列表，记录拼写和模板预设。
-   `@gusnips/one-click-dns/server`读取DNS，建立签名链接。Node或Bun。
-   `@gusnips/one-click-dns/writers`：写入带有API令牌的记录。服务器只。

将密钥和令牌保存在服务器上。浏览器条目中不需要它们。

## 第一个电话

```ts
import { planConnection, systemDnsLookups } from "@gusnips/one-click-dns/server";

const plan = await planConnection({ hostname: "help.acme.com" }, systemDnsLookups(2000));

console.log(plan.reading?.hosts); // ["cloudflare"]
console.log(plan.methods.map((method) => method.kind)); // ["api-token", "manual"]
```

`methods` 列出了联系的方式，最好是第一个：

| `kind` | 这意味着什么？ |
| --- | --- |
| `domain-connect` | 一个点击。你把这个人送到 `url`，他们的DNS主机要求他们批准，记录就会出现。 |
| `api-token` | 此人粘贴一个令牌，然后您的服务器写入该记录。 |
| `manual` | 这个人用手抄写记录。主人的名字在里面 `hosts`． 总是最后一个。 |

`plan.reading` 是 `null` DNS没有应答。这与“主机未知”不同，所以不要将其显示为一个。

## 添加带有令牌的记录

```ts
import { cloudflare } from "@gusnips/one-click-dns/writers";

const outcome = await cloudflare.addRecord({
  token, // the person's Cloudflare API token
  record: { type: "CNAME", name: "help.acme.com", value: "abc123.domains.example.app" },
});
// "created", "unchanged" or "unproxied"
```

令牌仅用于此调用。它永远不会被存储、记录或放入错误中。这个人已经有的记录永远不会被覆盖：你得到一个 `conflict` 代替。

当写入失败时，它抛出 `DnsWriteError` 与一个 `code`． 用你自己的语言编写代码：

| `code` | 告诉那个人什么 |
| --- | --- |
| `token_invalid` | 主机不接受令牌。再次粘贴。 |
| `zone_read_missing` | 令牌不能列出域。给它许可吧。 |
| `dns_edit_missing` | 令牌不能改变DNS记录。给它许可吧。 |
| `zone_not_found` | 令牌的帐户不包含此域。 |
| `conflict` | 这个名字已经有另一个记录了(`params.type`）. 他们决定如何处理它。 |
| `unavailable` | 主人没有回答。再试一次。 |

四位主持人今天有一位作家。每个人粘贴的内容是不同的。测试用的是假网络。Cloudflare和DigitalOcean也是在一个真实账户上运行的，使用的是虚构的下划线名称，之后会被删除。而Porkbun和Name.com则不然。

| 作家 | `token` 是 | 它需要什么 | 检查了多少 |
| --- | --- | --- | --- |
| `cloudflare` | API令牌 | `Zone:Read` 和 `DNS:Edit` | 在2026-10-29对真实区域运行：创建、重复、TXT、冲突和错误的令牌 |
| `porkbun` | `apikey:secretapikey` | “API访问”在Porkbun中为域打开（默认是关闭的） | 根据主机的API规范编写。从不针对真实帐户运行 |
| `digitalocean` | 个人访问令牌 | `domain:read` 和 `domain:create`，或完全访问 | 2026-10-29对一个真实的域运行：创建、重复、TXT、冲突和一个错误的令牌 |
| `name-com` | `username:apitoken` | 在帐户设置、安全中打开API访问 | 根据主持人的文档写的。永远不要与真实账户对账 |

`writers` 将主机id映射到它的写入器，所以 `writers[host]` 是 `undefined` 对于一个没有编剧的主持人来说。

### 根据你自己的账户核对一个作家

存储库有一个脚本，可以在真实区域上尝试写入器并删除它所创建的内容。使用一个备用区域和一个限制于此的令牌：

```bash
HOST=cloudflare ZONE=example.com TOKEN=your-token bun run live
```

它将CNAME和TXT记录写入虚构的下划线名称下，分别运行第二次（两者都必须读为“未改变”），检查冲突记录是否被拒绝，并报告错误的令牌，然后删除其记录。支持Cloudflare和DigitalOcean。

## 一键链接（域连接）

一个链接需要一个你的DNS主机已经开启的模板和一个密钥对。您在DNS中发布公钥，并将私钥保存在服务器上。

```ts
const plan = await planConnection(
  {
    hostname: "help.acme.com",
    connect: {
      providerId: "example.com", // your id in the Templates repository
      keyId: "_dck1", // the TXT record name that holds your public key
      serviceId: "custom-domain", // your template
      privateKeyPem,
      params: (zone) => ({
        domain: zone,
        host: "help",
        target: "abc123",
        redirect_uri: "https://app.example.com/done",
      }),
    },
  },
  systemDnsLookups(2000),
);
```

当主机有你的模板时， `plan.methods` 从a开始 `domain-connect` 方法。把人送回 `redirect_uri` 证明不了什么。在标记域完成之前，自己检查DNS。

只有这些提供者被要求，因为他们 `_domainconnect` 值和设置从DNS: Cloudflare， Vercel, Simply.com和GoDaddy读取。永远不会获取客户DNS中的名称。更多的提供者以同样的方式加入，一次一个值。

这里列出的提供商是包可以与之通信的提供商。这并不是说提供程序会打开你的模板。例如，GoDaddy在2026-10-29告诉我们，它不接受直接登录的新模板，也没有给出日期。询问每个提供者，并使用 `templateCoverage` 看看是谁答应了。没有联系的地方， `plan.methods` 仍然以主机的步骤结束。

### 哪些提供程序打开了您的模板

合并模板不是提供程序使用的模板。每个提供程序都手动打开模板，唯一的方法就是询问它。 `templateCoverage` 请求列表中的每个提供者一次：

```ts
import { templateCoverage } from "@gusnips/one-click-dns/server";

const coverage = await templateCoverage(
  {},
  { providerId: "example.com", serviceId: "custom-domain" },
);
// { cloudflare: "not_supported", godaddy: "supported", vercel: "not_supported", simply: "not_supported" }
```

`"unanswered"` 表示提供者很忙或没有回复。它从不意味着不。时不时地运行它，看看什么时候提供程序开始支持你的模板。

## 模板

模板是一个公开的小JSON文件 [域连接模板](https://github.com/Domain-Connect/Templates) 存储库。它列出了您可能要求主机添加的记录。预设构建一个遵循存储库规则的记录：

```ts
import { cnameTemplate, templateFileName } from "@gusnips/one-click-dns";

const template = cnameTemplate(
  {
    providerId: "example.com",
    providerName: "Example",
    logoUrl: "https://example.com/logo.svg",
    syncPubKeyDomain: "example.com",
    syncRedirectDomain: "app.example.com",
  },
  { pointsTo: "%target%.domains.example.com" },
);

console.log(templateFileName(template)); // "example.com.custom-domain.json"
```

有CNAME， DMARC， SPF， DKIM， MX和验证TXT的预设。

其中两个改变了域名电子邮件的工作方式。MX预设将替换域拥有的MX记录，因此它的邮件将转到其他地方。SPF预置将发送者添加到域的SPF记录中。在你提供任何一个链接之前，在你自己的屏幕上征求对方的同意，并说明模板的变化 `description`， DNS主机在批准时显示。

模板属于归档它的公司。它命名您的密钥域，主机根据在那里发布的密钥检查每个链接。所以你不能使用别人的模板，也没有人可以使用你的模板。客户的域不在模板中：它随每个链接一起提供，因此一个模板为每个客户服务。

文件中测试模板 [在线编辑器](https://domainconnect.paulonet.eu/dc/free/templateedit)、运行 `dc-template-linter -merge-or-fail` 打开一个pull request，然后要求每个DNS主机打开它。

### 保持单独的SPF服务

同一模板的两个链接可以替换彼此的记录，即使在发布任何一个链接之前检查DNS也是如此。对于SPF，这可以删除其他服务的发送权限。

当一个模板提供多个发送服务时，选择加入单独的实例：

```ts
const template = spfTemplate(identity, { multiInstance: true, version: 2 });
```

将更新后的模板归档，并等待DNS提供程序将其打开。在签署链接之前，要求该提供商的副本发布该标志：

```ts
import { discoverConnect, systemDnsLookups } from "@gusnips/one-click-dns/server";

const discovery = await discoverConnect(
  { txt: systemDnsLookups(2000).txt },
  {
    zone: "acme.com",
    providerId: "example.com",
    serviceId: "spf",
    budgetMs: 2000,
    requireMultiInstance: true,
  },
);
```

此检查需要提供程序条目和 `supportsMultiInstance: true` 和字面模板标志 `multiInstance: true`． 缺少或错误的支持返回 `not_offered`． 模板检查读取相同的受大小限制的响应，并且不发出额外的请求。其他发现调用保持当前的行为。

尚未有内置提供程序验证实例支持。 [Cloudflare说它忽略了这个标志](https://developers.cloudflare.com/dns/reference/domain-connect/#template-definition);其他提供程序未经验证。因此，要求实例返回 `not_offered` 对于每个内置提供程序。保持手动撤退。对于一个习惯 `providers` 列表,设置 `supportsMultiInstance: true` 只有在验证该提供者的行为之后，而不仅仅是它的模板JSON。

只有在需要的时候才签字 `discovery.found` 是真的。签名同步链接带有模板标志；规范定义了 `instanceId` 对于异步应用和恢复，而不是对于同步参数。如果稍后通过异步API删除一个应用程序，则传递一个稳定的 `instanceId` 来自完整发送域和服务的SPF包括：同一对重复使用相同的id，不同的域或服务使用不同的id。包不会为您选择该id。该标志不会检查SPF的查找限制，也不会重定向到您的应用程序，以证明DNS已更改。

## 主机步骤

`DNS_HOSTS` 拥有33个主机：如何从名称服务器，DNS页面上的标签和陷阱（默认情况下启用代理，尾随点，需要引号的TXT）中识别它们。该包包含数据而不包含句子，因此您可以用自己的单词和语言编写步骤。 `dnsRecordRow` 按主机希望输入的方式拼写记录：

```ts
import { dnsRecordRow } from "@gusnips/one-click-dns";

dnsRecordRow("route53", "acme.com", { type: "TXT", name: "acme.com", value: "v=spf1 ~all" });
// { type: "TXT", name: "", value: "\"v=spf1 ~all\"", atRoot: true, rootUnsure: false }
```

名称服务器模式只有在主机记录它或在DNS中看到它时才会出现在列表中。只有当主机自己的页面显示标签时，标签才会被引用。

## 检查

```bash
bun run lint
bun run typecheck
bun run build
bun test src/path/to/file.test.ts
```

## 常见问题

### @gusnips/one-click-dns 是什么？

将DNS记录放在客户的区域中：找到他们的DNS主机，将它们发送到签名的Domain Connect链接，使用API令牌编写，或显示该主机的步骤

### 如何安装 @gusnips/one-click-dns？

在项目目录运行 npm install @gusnips/one-click-dns，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：@gusnips/server（\>=0\.14\.3）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @gusnips/one-click-dns 支持 TypeScript 吗？

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

### @gusnips/one-click-dns 支持 ESM 还是 CommonJS？

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

### @gusnips/one-click-dns 需要什么版本的 Node\.js？

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

### @gusnips/one-click-dns 可以商用吗？

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

### @gusnips/one-click-dns 还在维护吗？

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

