@gusnips/one-click-dns 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -7
- package/dist/{chunk-4XNRV7QR.js → chunk-LLWYWMJ5.js} +6 -2
- package/dist/index.cjs +7 -4
- package/dist/index.d.cts +15 -3
- package/dist/index.d.ts +15 -3
- package/dist/index.js +7 -4
- package/dist/server/index.cjs +9 -2
- package/dist/server/index.js +4 -1
- package/dist/writers/index.cjs +6 -2
- package/dist/writers/index.js +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -62,17 +62,27 @@ When the write fails, it throws a `DnsWriteError` with a `code`. Word each code
|
|
|
62
62
|
| `conflict` | The name already has another record (`params.type`). They decide what to do with it. |
|
|
63
63
|
| `unavailable` | The host did not answer. Try again. |
|
|
64
64
|
|
|
65
|
-
Four hosts have a writer today. What the person pastes is different for each.
|
|
65
|
+
Four hosts have a writer today. What the person pastes is different for each. The tests use a fake network. Cloudflare and DigitalOcean were also run against a real account, with made-up underscore names that were deleted after. Porkbun and Name.com were not:
|
|
66
66
|
|
|
67
|
-
| Writer | `token` is | What it needs | How far it is checked
|
|
68
|
-
| -------------- | ----------------------- | ----------------------------------------------------------------------- |
|
|
69
|
-
| `cloudflare` | An API token | `Zone:Read` and `DNS:Edit` |
|
|
70
|
-
| `porkbun` | `apikey:secretapikey` | "API access" turned on for the domain in Porkbun (it is off by default) | Written from the host's API spec. Never run against a real account
|
|
71
|
-
| `digitalocean` | A personal access token | `domain:read` and `domain:create`, or full access |
|
|
72
|
-
| `name-com` | `username:apitoken` | API access turned on in Account Settings, Security | Written from the host's docs. Never run against a real account
|
|
67
|
+
| Writer | `token` is | What it needs | How far it is checked |
|
|
68
|
+
| -------------- | ----------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
69
|
+
| `cloudflare` | An API token | `Zone:Read` and `DNS:Edit` | Run against a real zone on 2026-10-29: create, repeat, TXT, conflicts and a wrong token |
|
|
70
|
+
| `porkbun` | `apikey:secretapikey` | "API access" turned on for the domain in Porkbun (it is off by default) | Written from the host's API spec. Never run against a real account |
|
|
71
|
+
| `digitalocean` | A personal access token | `domain:read` and `domain:create`, or full access | Run against a real domain on 2026-10-29: create, repeat, TXT, conflicts and a wrong token |
|
|
72
|
+
| `name-com` | `username:apitoken` | API access turned on in Account Settings, Security | Written from the host's docs. Never run against a real account |
|
|
73
73
|
|
|
74
74
|
`writers` maps a host id to its writer, so `writers[host]` is `undefined` for a host with no writer.
|
|
75
75
|
|
|
76
|
+
### Check a writer against your own account
|
|
77
|
+
|
|
78
|
+
The repository has a script that tries a writer on a real zone and removes what it made. Use a spare zone and a token limited to it:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
HOST=cloudflare ZONE=example.com TOKEN=your-token bun run live
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
It writes a CNAME and a TXT record under made-up underscore names, runs each a second time (both must read as "unchanged"), checks that a clashing record is refused and that a wrong token is reported as one, then deletes its records. Cloudflare and DigitalOcean are supported.
|
|
85
|
+
|
|
76
86
|
## One-click links (Domain Connect)
|
|
77
87
|
|
|
78
88
|
A link needs a template that your DNS host has switched on, and a key pair. You publish the public key in DNS and keep the private key on your server.
|
|
@@ -102,6 +112,8 @@ When the host has your template, `plan.methods` starts with a `domain-connect` m
|
|
|
102
112
|
|
|
103
113
|
Only these providers are asked, because their `_domainconnect` value and settings were read from DNS: Cloudflare, Vercel, Simply.com and GoDaddy. A name in a customer's DNS is never fetched. More providers join the same way, one value at a time.
|
|
104
114
|
|
|
115
|
+
A provider listed here is one the package can talk to. It is not a promise that the provider will switch your template on. GoDaddy, for one, told us on 2026-10-29 that it is not accepting new templates for direct onboarding and gave no date. Ask each provider, and use `templateCoverage` to see who said yes. Where there is no link, `plan.methods` still ends with the steps for that host.
|
|
116
|
+
|
|
105
117
|
### Which providers have switched your template on
|
|
106
118
|
|
|
107
119
|
A merged template is not a template a provider uses. Each provider turns templates on by hand, and the only way to know is to ask it. `templateCoverage` asks every provider in the list once:
|
|
@@ -141,6 +153,8 @@ console.log(templateFileName(template)); // "example.com.custom-domain.json"
|
|
|
141
153
|
|
|
142
154
|
There are presets for a CNAME, DMARC, SPF, DKIM, MX and a verification TXT.
|
|
143
155
|
|
|
156
|
+
Two of them change how a domain's email works. The MX preset replaces the MX records the domain has, so its mail goes somewhere else. The SPF preset adds a sender to the domain's SPF record. Ask the person for consent in your own screen before you offer either link, and say what changes in the template's `description`, which the DNS host shows when they approve.
|
|
157
|
+
|
|
144
158
|
A template belongs to the company that files it. It names your key domain, and the host checks every link against the key published there. So you cannot use someone else's template, and nobody can use yours. The customer's domain is not in the template: it comes with each link, so one template serves every customer.
|
|
145
159
|
|
|
146
160
|
To file a template: test it in the [online editor](https://domainconnect.paulonet.eu/dc/free/templateedit), run `dc-template-linter -merge-or-fail` on it, open a pull request, then ask each DNS host to switch it on.
|
|
@@ -81,23 +81,26 @@ var API = "https://api.cloudflare.com/client/v4";
|
|
|
81
81
|
var TIMEOUT_MS = 1e4;
|
|
82
82
|
var MAX_BODY_BYTES = 256 * 1024;
|
|
83
83
|
var TOKEN_CODES = /* @__PURE__ */ new Set([1e3, 6003, 6111, 1e4]);
|
|
84
|
+
var INVALID_TOKEN_MESSAGE = /invalid access token/i;
|
|
84
85
|
var CONFLICT_CODES = /* @__PURE__ */ new Set([81053, 81054, 81057]);
|
|
85
86
|
var ID = /^[A-Za-z0-9]{1,64}$/;
|
|
86
87
|
var RECORD_TYPE = /^[A-Z0-9]{1,12}$/;
|
|
87
88
|
function readEnvelope(json) {
|
|
88
89
|
if (!isObject(json) || typeof json.success !== "boolean") return null;
|
|
89
90
|
const codes = [];
|
|
91
|
+
const messages = [];
|
|
90
92
|
if (Array.isArray(json.errors)) {
|
|
91
93
|
for (const error of json.errors) {
|
|
92
94
|
if (!isObject(error)) return null;
|
|
93
95
|
if (typeof error.code === "number") codes.push(error.code);
|
|
96
|
+
if (typeof error.message === "string") messages.push(error.message);
|
|
94
97
|
if (Array.isArray(error.error_chain)) {
|
|
95
98
|
for (const link of error.error_chain)
|
|
96
99
|
if (isObject(link) && typeof link.code === "number") codes.push(link.code);
|
|
97
100
|
}
|
|
98
101
|
}
|
|
99
102
|
}
|
|
100
|
-
return { success: json.success, codes, result: json.result };
|
|
103
|
+
return { success: json.success, codes, messages, result: json.result };
|
|
101
104
|
}
|
|
102
105
|
async function call(doFetch, token, path, send) {
|
|
103
106
|
const res = await fetchBounded(
|
|
@@ -124,7 +127,8 @@ async function call(doFetch, token, path, send) {
|
|
|
124
127
|
}
|
|
125
128
|
function refusal(answer, stage, subject) {
|
|
126
129
|
const codes = answer.body?.codes ?? [];
|
|
127
|
-
const
|
|
130
|
+
const messages = answer.body?.messages ?? [];
|
|
131
|
+
const refusedToken = answer.status === 401 || codes.some((c) => TOKEN_CODES.has(c)) || messages.some((m) => INVALID_TOKEN_MESSAGE.test(m));
|
|
128
132
|
if (stage === "zones" && refusedToken) return new DnsWriteError("token_invalid");
|
|
129
133
|
if (codes.some((c) => CONFLICT_CODES.has(c)))
|
|
130
134
|
return new DnsWriteError("conflict", { ...subject });
|
package/dist/index.cjs
CHANGED
|
@@ -663,21 +663,24 @@ function spfTemplate(identity, options = {}) {
|
|
|
663
663
|
);
|
|
664
664
|
}
|
|
665
665
|
function dkimTemplate(identity, options = {}) {
|
|
666
|
-
const
|
|
666
|
+
const { selectors } = options;
|
|
667
|
+
const keys = selectors?.length ?? options.keys ?? 2;
|
|
667
668
|
const numbers = Array.from({ length: keys }, (_, index) => index + 1);
|
|
669
|
+
const hostOf = (n) => selectors ? `${selectors[n - 1]}._domainkey` : `%selector${n}%._domainkey`;
|
|
670
|
+
const describe = (n) => selectors ? `%target${n}%: where ${selectors[n - 1]}._domainkey points` : `%selector${n}%: the key name, ${n} of ${keys}; %target${n}%: where it points`;
|
|
668
671
|
return template(
|
|
669
672
|
identity,
|
|
670
673
|
"dkim",
|
|
671
674
|
{
|
|
672
675
|
serviceName: "Sign your email with our key",
|
|
673
676
|
description: "Adds the CNAME records that let us sign email sent from your domain.",
|
|
674
|
-
variableDescription: numbers.map(
|
|
677
|
+
variableDescription: options.variableDescription ?? numbers.map(describe).join("; ")
|
|
675
678
|
},
|
|
676
679
|
options,
|
|
677
680
|
numbers.map((n) => ({
|
|
678
681
|
type: "CNAME",
|
|
679
|
-
host:
|
|
680
|
-
pointsTo: `%target${n}%`,
|
|
682
|
+
host: hostOf(n),
|
|
683
|
+
pointsTo: options.pointsTo?.(n) ?? `%target${n}%`,
|
|
681
684
|
ttl: TTL
|
|
682
685
|
}))
|
|
683
686
|
);
|
package/dist/index.d.cts
CHANGED
|
@@ -99,12 +99,24 @@ declare function dmarcTemplate(identity: TemplateIdentity, options?: Wording & {
|
|
|
99
99
|
/** Adds one `include:` to the domain's SPF record. `SPFM` merges it into the one record the
|
|
100
100
|
* name may have; a TXT would make a second one and break SPF. The link carries `%include%`. */
|
|
101
101
|
declare function spfTemplate(identity: TemplateIdentity, options?: Wording): DomainConnectTemplate;
|
|
102
|
-
/**
|
|
103
|
-
*
|
|
102
|
+
/**
|
|
103
|
+
* DKIM as CNAMEs, for services that publish the key on their side.
|
|
104
|
+
*
|
|
105
|
+
* By default the link carries `%selector1%` and `%target1%`, then the same pair numbered up to
|
|
106
|
+
* `keys`. When your key names never change, fix them: `selectors: ["cd1", "cd2"]` writes
|
|
107
|
+
* `cd1._domainkey` and `cd2._domainkey` into the template, which the repository prefers to a
|
|
108
|
+
* variable. `pointsTo` then names where each CNAME goes (`(n) => "%dkim" + n + "%.example.net"`),
|
|
109
|
+
* and `variableDescription` says what its variables mean.
|
|
110
|
+
*/
|
|
104
111
|
declare function dkimTemplate(identity: TemplateIdentity, options?: Wording & {
|
|
105
112
|
keys?: number;
|
|
113
|
+
selectors?: readonly string[];
|
|
114
|
+
pointsTo?: (n: number) => string;
|
|
115
|
+
variableDescription?: string;
|
|
106
116
|
}): DomainConnectTemplate;
|
|
107
|
-
/** The MX record that sends the domain's mail to you.
|
|
117
|
+
/** The MX record that sends the domain's mail to you. It changes where the domain's email is
|
|
118
|
+
* delivered and replaces the MX records it has, so ask the person for consent before you offer
|
|
119
|
+
* the link; say so in `description` too. */
|
|
108
120
|
declare function mxTemplate(identity: TemplateIdentity, options: Wording & {
|
|
109
121
|
pointsTo: string;
|
|
110
122
|
priority?: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -99,12 +99,24 @@ declare function dmarcTemplate(identity: TemplateIdentity, options?: Wording & {
|
|
|
99
99
|
/** Adds one `include:` to the domain's SPF record. `SPFM` merges it into the one record the
|
|
100
100
|
* name may have; a TXT would make a second one and break SPF. The link carries `%include%`. */
|
|
101
101
|
declare function spfTemplate(identity: TemplateIdentity, options?: Wording): DomainConnectTemplate;
|
|
102
|
-
/**
|
|
103
|
-
*
|
|
102
|
+
/**
|
|
103
|
+
* DKIM as CNAMEs, for services that publish the key on their side.
|
|
104
|
+
*
|
|
105
|
+
* By default the link carries `%selector1%` and `%target1%`, then the same pair numbered up to
|
|
106
|
+
* `keys`. When your key names never change, fix them: `selectors: ["cd1", "cd2"]` writes
|
|
107
|
+
* `cd1._domainkey` and `cd2._domainkey` into the template, which the repository prefers to a
|
|
108
|
+
* variable. `pointsTo` then names where each CNAME goes (`(n) => "%dkim" + n + "%.example.net"`),
|
|
109
|
+
* and `variableDescription` says what its variables mean.
|
|
110
|
+
*/
|
|
104
111
|
declare function dkimTemplate(identity: TemplateIdentity, options?: Wording & {
|
|
105
112
|
keys?: number;
|
|
113
|
+
selectors?: readonly string[];
|
|
114
|
+
pointsTo?: (n: number) => string;
|
|
115
|
+
variableDescription?: string;
|
|
106
116
|
}): DomainConnectTemplate;
|
|
107
|
-
/** The MX record that sends the domain's mail to you.
|
|
117
|
+
/** The MX record that sends the domain's mail to you. It changes where the domain's email is
|
|
118
|
+
* delivered and replaces the MX records it has, so ask the person for consent before you offer
|
|
119
|
+
* the link; say so in `description` too. */
|
|
108
120
|
declare function mxTemplate(identity: TemplateIdentity, options: Wording & {
|
|
109
121
|
pointsTo: string;
|
|
110
122
|
priority?: number;
|
package/dist/index.js
CHANGED
|
@@ -117,21 +117,24 @@ function spfTemplate(identity, options = {}) {
|
|
|
117
117
|
);
|
|
118
118
|
}
|
|
119
119
|
function dkimTemplate(identity, options = {}) {
|
|
120
|
-
const
|
|
120
|
+
const { selectors } = options;
|
|
121
|
+
const keys = selectors?.length ?? options.keys ?? 2;
|
|
121
122
|
const numbers = Array.from({ length: keys }, (_, index) => index + 1);
|
|
123
|
+
const hostOf = (n) => selectors ? `${selectors[n - 1]}._domainkey` : `%selector${n}%._domainkey`;
|
|
124
|
+
const describe = (n) => selectors ? `%target${n}%: where ${selectors[n - 1]}._domainkey points` : `%selector${n}%: the key name, ${n} of ${keys}; %target${n}%: where it points`;
|
|
122
125
|
return template(
|
|
123
126
|
identity,
|
|
124
127
|
"dkim",
|
|
125
128
|
{
|
|
126
129
|
serviceName: "Sign your email with our key",
|
|
127
130
|
description: "Adds the CNAME records that let us sign email sent from your domain.",
|
|
128
|
-
variableDescription: numbers.map(
|
|
131
|
+
variableDescription: options.variableDescription ?? numbers.map(describe).join("; ")
|
|
129
132
|
},
|
|
130
133
|
options,
|
|
131
134
|
numbers.map((n) => ({
|
|
132
135
|
type: "CNAME",
|
|
133
|
-
host:
|
|
134
|
-
pointsTo: `%target${n}%`,
|
|
136
|
+
host: hostOf(n),
|
|
137
|
+
pointsTo: options.pointsTo?.(n) ?? `%target${n}%`,
|
|
135
138
|
ttl: TTL
|
|
136
139
|
}))
|
|
137
140
|
);
|
package/dist/server/index.cjs
CHANGED
|
@@ -647,6 +647,9 @@ var CONNECT_PROVIDERS = [
|
|
|
647
647
|
// Settings read 2026-10-29 from domainconnect.api.godaddy.com (`urlSyncUX`
|
|
648
648
|
// https://dcc.godaddy.com/manage). The TXT value on a customer's zone is not read yet: if it
|
|
649
649
|
// differs, GoDaddy answers "not offered", which is the safe way to be wrong.
|
|
650
|
+
// GoDaddy told us on 2026-10-29 that it is "not currently accepting new templates for direct
|
|
651
|
+
// onboarding", with no timeline. It supports many templates already (9 of 12 third-party ones
|
|
652
|
+
// we probed), so the entry stays for them, but a template of yours answers "not offered" there.
|
|
650
653
|
{
|
|
651
654
|
id: "godaddy",
|
|
652
655
|
txt: "domainconnect.api.godaddy.com",
|
|
@@ -858,23 +861,26 @@ var API = "https://api.cloudflare.com/client/v4";
|
|
|
858
861
|
var TIMEOUT_MS = 1e4;
|
|
859
862
|
var MAX_BODY_BYTES = 256 * 1024;
|
|
860
863
|
var TOKEN_CODES = /* @__PURE__ */ new Set([1e3, 6003, 6111, 1e4]);
|
|
864
|
+
var INVALID_TOKEN_MESSAGE = /invalid access token/i;
|
|
861
865
|
var CONFLICT_CODES = /* @__PURE__ */ new Set([81053, 81054, 81057]);
|
|
862
866
|
var ID = /^[A-Za-z0-9]{1,64}$/;
|
|
863
867
|
var RECORD_TYPE = /^[A-Z0-9]{1,12}$/;
|
|
864
868
|
function readEnvelope(json) {
|
|
865
869
|
if (!isObject(json) || typeof json.success !== "boolean") return null;
|
|
866
870
|
const codes = [];
|
|
871
|
+
const messages = [];
|
|
867
872
|
if (Array.isArray(json.errors)) {
|
|
868
873
|
for (const error of json.errors) {
|
|
869
874
|
if (!isObject(error)) return null;
|
|
870
875
|
if (typeof error.code === "number") codes.push(error.code);
|
|
876
|
+
if (typeof error.message === "string") messages.push(error.message);
|
|
871
877
|
if (Array.isArray(error.error_chain)) {
|
|
872
878
|
for (const link of error.error_chain)
|
|
873
879
|
if (isObject(link) && typeof link.code === "number") codes.push(link.code);
|
|
874
880
|
}
|
|
875
881
|
}
|
|
876
882
|
}
|
|
877
|
-
return { success: json.success, codes, result: json.result };
|
|
883
|
+
return { success: json.success, codes, messages, result: json.result };
|
|
878
884
|
}
|
|
879
885
|
async function call(doFetch, token, path, send) {
|
|
880
886
|
const res = await fetchBounded(
|
|
@@ -901,7 +907,8 @@ async function call(doFetch, token, path, send) {
|
|
|
901
907
|
}
|
|
902
908
|
function refusal(answer, stage, subject) {
|
|
903
909
|
const codes = answer.body?.codes ?? [];
|
|
904
|
-
const
|
|
910
|
+
const messages = answer.body?.messages ?? [];
|
|
911
|
+
const refusedToken = answer.status === 401 || codes.some((c) => TOKEN_CODES.has(c)) || messages.some((m) => INVALID_TOKEN_MESSAGE.test(m));
|
|
905
912
|
if (stage === "zones" && refusedToken) return new DnsWriteError("token_invalid");
|
|
906
913
|
if (codes.some((c) => CONFLICT_CODES.has(c)))
|
|
907
914
|
return new DnsWriteError("conflict", { ...subject });
|
package/dist/server/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
fetchBounded,
|
|
6
6
|
isObject,
|
|
7
7
|
writers
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-LLWYWMJ5.js";
|
|
9
9
|
import {
|
|
10
10
|
normalizeDnsName
|
|
11
11
|
} from "../chunk-P2O7INDB.js";
|
|
@@ -112,6 +112,9 @@ var CONNECT_PROVIDERS = [
|
|
|
112
112
|
// Settings read 2026-10-29 from domainconnect.api.godaddy.com (`urlSyncUX`
|
|
113
113
|
// https://dcc.godaddy.com/manage). The TXT value on a customer's zone is not read yet: if it
|
|
114
114
|
// differs, GoDaddy answers "not offered", which is the safe way to be wrong.
|
|
115
|
+
// GoDaddy told us on 2026-10-29 that it is "not currently accepting new templates for direct
|
|
116
|
+
// onboarding", with no timeline. It supports many templates already (9 of 12 third-party ones
|
|
117
|
+
// we probed), so the entry stays for them, but a template of yours answers "not offered" there.
|
|
115
118
|
{
|
|
116
119
|
id: "godaddy",
|
|
117
120
|
txt: "domainconnect.api.godaddy.com",
|
package/dist/writers/index.cjs
CHANGED
|
@@ -113,23 +113,26 @@ var API = "https://api.cloudflare.com/client/v4";
|
|
|
113
113
|
var TIMEOUT_MS = 1e4;
|
|
114
114
|
var MAX_BODY_BYTES = 256 * 1024;
|
|
115
115
|
var TOKEN_CODES = /* @__PURE__ */ new Set([1e3, 6003, 6111, 1e4]);
|
|
116
|
+
var INVALID_TOKEN_MESSAGE = /invalid access token/i;
|
|
116
117
|
var CONFLICT_CODES = /* @__PURE__ */ new Set([81053, 81054, 81057]);
|
|
117
118
|
var ID = /^[A-Za-z0-9]{1,64}$/;
|
|
118
119
|
var RECORD_TYPE = /^[A-Z0-9]{1,12}$/;
|
|
119
120
|
function readEnvelope(json) {
|
|
120
121
|
if (!isObject(json) || typeof json.success !== "boolean") return null;
|
|
121
122
|
const codes = [];
|
|
123
|
+
const messages = [];
|
|
122
124
|
if (Array.isArray(json.errors)) {
|
|
123
125
|
for (const error of json.errors) {
|
|
124
126
|
if (!isObject(error)) return null;
|
|
125
127
|
if (typeof error.code === "number") codes.push(error.code);
|
|
128
|
+
if (typeof error.message === "string") messages.push(error.message);
|
|
126
129
|
if (Array.isArray(error.error_chain)) {
|
|
127
130
|
for (const link of error.error_chain)
|
|
128
131
|
if (isObject(link) && typeof link.code === "number") codes.push(link.code);
|
|
129
132
|
}
|
|
130
133
|
}
|
|
131
134
|
}
|
|
132
|
-
return { success: json.success, codes, result: json.result };
|
|
135
|
+
return { success: json.success, codes, messages, result: json.result };
|
|
133
136
|
}
|
|
134
137
|
async function call(doFetch, token, path, send) {
|
|
135
138
|
const res = await fetchBounded(
|
|
@@ -156,7 +159,8 @@ async function call(doFetch, token, path, send) {
|
|
|
156
159
|
}
|
|
157
160
|
function refusal(answer, stage, subject) {
|
|
158
161
|
const codes = answer.body?.codes ?? [];
|
|
159
|
-
const
|
|
162
|
+
const messages = answer.body?.messages ?? [];
|
|
163
|
+
const refusedToken = answer.status === 401 || codes.some((c) => TOKEN_CODES.has(c)) || messages.some((m) => INVALID_TOKEN_MESSAGE.test(m));
|
|
160
164
|
if (stage === "zones" && refusedToken) return new DnsWriteError("token_invalid");
|
|
161
165
|
if (codes.some((c) => CONFLICT_CODES.has(c)))
|
|
162
166
|
return new DnsWriteError("conflict", { ...subject });
|
package/dist/writers/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gusnips/one-click-dns",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"packageManager": "bun@1.4.2",
|
|
5
5
|
"description": "Put DNS records in a customer's zone: find their DNS host, send them to a signed Domain Connect link, write with an API token, or show the steps for that host",
|
|
6
6
|
"type": "module",
|
|
@@ -47,9 +47,10 @@
|
|
|
47
47
|
"scripts": {
|
|
48
48
|
"build": "tsup src/index.ts src/server/index.ts src/writers/index.ts --format cjs,esm --dts --clean",
|
|
49
49
|
"typecheck": "tsc --noEmit",
|
|
50
|
-
"lint": "eslint src",
|
|
50
|
+
"lint": "eslint src scripts",
|
|
51
51
|
"format": "prettier --write .",
|
|
52
52
|
"test": "bun test",
|
|
53
|
+
"live": "bun scripts/live-check.ts",
|
|
53
54
|
"prepublishOnly": "bun run lint && bun run typecheck && bun run build"
|
|
54
55
|
},
|
|
55
56
|
"keywords": [
|