@gusnips/one-click-dns 0.1.0 → 0.1.2

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.
@@ -22,6 +22,9 @@ var writers_exports = {};
22
22
  __export(writers_exports, {
23
23
  DnsWriteError: () => DnsWriteError,
24
24
  cloudflare: () => cloudflare,
25
+ digitalocean: () => digitalocean,
26
+ namecom: () => namecom,
27
+ porkbun: () => porkbun,
25
28
  writers: () => writers
26
29
  });
27
30
  module.exports = __toCommonJS(writers_exports);
@@ -29,22 +32,25 @@ module.exports = __toCommonJS(writers_exports);
29
32
  // src/bounded-fetch.ts
30
33
  var import_server = require("@gusnips/server");
31
34
  async function fetchBounded(doFetch, url, init, limits) {
32
- try {
33
- const res = await doFetch(url, {
34
- ...init,
35
- redirect: "manual",
36
- signal: AbortSignal.timeout(limits.timeoutMs)
37
- });
38
- if (res.type === "opaqueredirect" || res.status >= 300 && res.status < 400) {
39
- await res.body?.cancel().catch(() => void 0);
40
- return { status: res.status || 302, text: "" };
35
+ const signal = AbortSignal.timeout(limits.timeoutMs);
36
+ const outOfTime = new Promise((resolve) => {
37
+ signal.addEventListener("abort", () => resolve(null), { once: true });
38
+ });
39
+ const attempt = async () => {
40
+ try {
41
+ const res = await doFetch(url, { ...init, redirect: "manual", signal });
42
+ if (res.type === "opaqueredirect" || res.status >= 300 && res.status < 400) {
43
+ await res.body?.cancel().catch(() => void 0);
44
+ return { status: res.status || 302, text: "" };
45
+ }
46
+ const { bytes, truncated } = await (0, import_server.readBounded)(res.body, limits.maxBytes);
47
+ if (truncated) return null;
48
+ return { status: res.status, text: new TextDecoder().decode(bytes) };
49
+ } catch {
50
+ return null;
41
51
  }
42
- const { bytes, truncated } = await (0, import_server.readBounded)(res.body, limits.maxBytes);
43
- if (truncated) return null;
44
- return { status: res.status, text: new TextDecoder().decode(bytes) };
45
- } catch {
46
- return null;
47
- }
52
+ };
53
+ return Promise.race([attempt(), outOfTime]);
48
54
  }
49
55
 
50
56
  // src/dns-name.ts
@@ -73,10 +79,35 @@ var MESSAGES = {
73
79
  zone_read_missing: () => "That token can't read your domains",
74
80
  dns_edit_missing: () => "That token can't change DNS records",
75
81
  zone_not_found: (p) => `No zone holds ${p.hostname ?? "that name"}`,
76
- conflict: (p) => `${p.hostname ?? "That name"} already has a record (type ${p.type ?? "?"})`,
82
+ conflict: (p) => `${p.hostname ?? "That name"} already has a record${p.type ? ` (type ${p.type})` : ""}`,
77
83
  unavailable: () => "Couldn't reach the DNS host"
78
84
  };
79
85
 
86
+ // src/writers/policy.ts
87
+ function zoneCandidates(hostname) {
88
+ const labels = hostname.split(".");
89
+ const names = [];
90
+ for (let start = 0; start < labels.length - 1; start++) names.push(labels.slice(start).join("."));
91
+ return names;
92
+ }
93
+ var unquoted = (content) => content.replace(/"\s+"/g, "").replace(/^"|"$/g, "");
94
+ var sameValue = (record, existing) => record.type === "CNAME" ? normalizeDnsName(existing.content) === normalizeDnsName(record.value) : unquoted(existing.content) === record.value;
95
+ var isSpf = (text) => /^v=spf1(?:\s|$)/i.test(unquoted(text).trim());
96
+ function blocks(record, existing) {
97
+ if (record.type === "CNAME" || existing.type === "CNAME") return true;
98
+ return existing.type === "TXT" && isSpf(record.value) && isSpf(existing.content);
99
+ }
100
+ function decide(record, existing, hostname) {
101
+ const ours = existing.find((r) => r.type === record.type && sameValue(record, r));
102
+ if (ours) {
103
+ if (record.type === "CNAME" && ours.proxied === true) return { kind: "unproxy", id: ours.id };
104
+ return { kind: "unchanged" };
105
+ }
106
+ const blocker = existing.find((r) => blocks(record, r));
107
+ if (blocker) throw new DnsWriteError("conflict", { hostname, type: blocker.type });
108
+ return { kind: "create" };
109
+ }
110
+
80
111
  // src/writers/cloudflare.ts
81
112
  var API = "https://api.cloudflare.com/client/v4";
82
113
  var TIMEOUT_MS = 1e4;
@@ -162,19 +193,6 @@ function recordsOf(result) {
162
193
  };
163
194
  });
164
195
  }
165
- function zoneCandidates(hostname) {
166
- const labels = hostname.split(".");
167
- const names = [];
168
- for (let start = 0; start < labels.length - 1; start++) names.push(labels.slice(start).join("."));
169
- return names;
170
- }
171
- var unquoted = (content) => content.replace(/"\s+"/g, "").replace(/^"|"$/g, "");
172
- var sameValue = (record, existing) => record.type === "CNAME" ? normalizeDnsName(existing.content) === normalizeDnsName(record.value) : unquoted(existing.content) === record.value;
173
- var isSpf = (text) => /^v=spf1(?:\s|$)/i.test(unquoted(text).trim());
174
- function blocks(record, existing) {
175
- if (record.type === "CNAME" || existing.type === "CNAME") return true;
176
- return existing.type === "TXT" && isSpf(record.value) && isSpf(existing.content);
177
- }
178
196
  var cloudflare = {
179
197
  host: "cloudflare",
180
198
  /** Add the record (DNS only) to the Cloudflare zone that holds its name. An identical record
@@ -203,11 +221,11 @@ var cloudflare = {
203
221
  subject
204
222
  )
205
223
  );
206
- const ours = existing.find((r) => r.type === record.type && sameValue(record, r));
207
- if (ours) {
208
- if (record.type !== "CNAME" || ours.proxied !== true) return "unchanged";
224
+ const decision = decide(record, existing, hostname);
225
+ if (decision.kind === "unchanged") return "unchanged";
226
+ if (decision.kind === "unproxy") {
209
227
  resultOf(
210
- await call(doFetch, token, `/zones/${zoneId}/dns_records/${ours.id}`, {
228
+ await call(doFetch, token, `/zones/${zoneId}/dns_records/${decision.id}`, {
211
229
  method: "PATCH",
212
230
  body: { proxied: false }
213
231
  }),
@@ -216,8 +234,6 @@ var cloudflare = {
216
234
  );
217
235
  return "unproxied";
218
236
  }
219
- const blocker = existing.find((r) => blocks(record, r));
220
- if (blocker) throw new DnsWriteError("conflict", { hostname, type: blocker.type });
221
237
  resultOf(
222
238
  await call(doFetch, token, `/zones/${zoneId}/dns_records`, {
223
239
  method: "POST",
@@ -239,11 +255,304 @@ var cloudflare = {
239
255
  }
240
256
  };
241
257
 
258
+ // src/writers/digitalocean.ts
259
+ var API2 = "https://api.digitalocean.com/v2";
260
+ var TIMEOUT_MS2 = 1e4;
261
+ var MAX_BODY_BYTES2 = 512 * 1024;
262
+ var RECORD_TYPE2 = /^[A-Z0-9]{1,12}$/;
263
+ async function call2(doFetch, token, path, send) {
264
+ const res = await fetchBounded(
265
+ doFetch,
266
+ `${API2}${path}`,
267
+ {
268
+ method: send ? "POST" : "GET",
269
+ headers: {
270
+ Authorization: `Bearer ${token}`,
271
+ Accept: "application/json",
272
+ ...send ? { "Content-Type": "application/json" } : {}
273
+ },
274
+ body: send ? JSON.stringify(send.body) : void 0
275
+ },
276
+ { timeoutMs: TIMEOUT_MS2, maxBytes: MAX_BODY_BYTES2 }
277
+ );
278
+ if (!res) return { status: 0, body: null };
279
+ let json = null;
280
+ try {
281
+ json = JSON.parse(res.text);
282
+ } catch {
283
+ }
284
+ return { status: res.status, body: isObject(json) ? json : null };
285
+ }
286
+ function refusal2(answer, stage, hostname) {
287
+ if (answer.status === 401) return new DnsWriteError("token_invalid");
288
+ if (answer.status === 403)
289
+ return new DnsWriteError(stage === "reading" ? "zone_read_missing" : "dns_edit_missing");
290
+ if (answer.status === 422 && stage === "writing")
291
+ return new DnsWriteError("conflict", { hostname });
292
+ return new DnsWriteError("unavailable");
293
+ }
294
+ function recordsOf2(body) {
295
+ const rows = body?.domain_records;
296
+ if (!Array.isArray(rows)) throw new DnsWriteError("unavailable");
297
+ return rows.map((row) => {
298
+ if (!isObject(row) || typeof row.id !== "number" || typeof row.type !== "string" || typeof row.data !== "string" || !RECORD_TYPE2.test(row.type))
299
+ throw new DnsWriteError("unavailable");
300
+ return { id: String(row.id), type: row.type, content: row.data };
301
+ });
302
+ }
303
+ var digitalocean = {
304
+ host: "digitalocean",
305
+ /** Add the record to the DigitalOcean domain that holds its name. An identical record is left
306
+ * as it is. DigitalOcean has no proxy, so the outcome is `created` or `unchanged`. */
307
+ async addRecord({ token, record, fetch: doFetch = fetch }) {
308
+ const hostname = normalizeDnsName(record.name);
309
+ let zone;
310
+ let existing = [];
311
+ for (const candidate of zoneCandidates(hostname)) {
312
+ const query = new URLSearchParams({ name: hostname, per_page: "200" });
313
+ const answer = await call2(
314
+ doFetch,
315
+ token,
316
+ `/domains/${encodeURIComponent(candidate)}/records?${query}`
317
+ );
318
+ if (answer.status === 200) {
319
+ zone = candidate;
320
+ existing = recordsOf2(answer.body);
321
+ break;
322
+ }
323
+ if (answer.status !== 404) throw refusal2(answer, "reading", hostname);
324
+ }
325
+ if (!zone) throw new DnsWriteError("zone_not_found", { hostname });
326
+ const decision = decide(record, existing, hostname);
327
+ if (decision.kind === "unchanged") return "unchanged";
328
+ const name = hostname === zone ? "@" : hostname.slice(0, -(zone.length + 1));
329
+ const created = await call2(doFetch, token, `/domains/${encodeURIComponent(zone)}/records`, {
330
+ body: {
331
+ type: record.type,
332
+ name,
333
+ data: record.type === "CNAME" ? `${normalizeDnsName(record.value)}.` : record.value,
334
+ // The API lists these as required for a TXT; they mean nothing for one.
335
+ ...record.type === "TXT" ? { flags: null, tag: null } : {}
336
+ }
337
+ });
338
+ if (created.status !== 201) throw refusal2(created, "writing", hostname);
339
+ return "created";
340
+ }
341
+ };
342
+
343
+ // src/writers/namecom.ts
344
+ var API3 = "https://api.name.com/core/v1";
345
+ var TIMEOUT_MS3 = 1e4;
346
+ var MAX_BODY_BYTES3 = 512 * 1024;
347
+ var PER_PAGE = 500;
348
+ var MAX_PAGES = 10;
349
+ var TTL = 300;
350
+ var RECORD_TYPE3 = /^[A-Z0-9]{1,12}$/;
351
+ function basicOf(token) {
352
+ const at = token.indexOf(":");
353
+ return at > 0 && at < token.length - 1 && !/\s/.test(token) ? btoa(token) : null;
354
+ }
355
+ async function call3(doFetch, basic, path, send) {
356
+ const res = await fetchBounded(
357
+ doFetch,
358
+ `${API3}${path}`,
359
+ {
360
+ method: send ? "POST" : "GET",
361
+ headers: {
362
+ Authorization: `Basic ${basic}`,
363
+ Accept: "application/json",
364
+ ...send ? { "Content-Type": "application/json" } : {}
365
+ },
366
+ body: send ? JSON.stringify(send.body) : void 0
367
+ },
368
+ { timeoutMs: TIMEOUT_MS3, maxBytes: MAX_BODY_BYTES3 }
369
+ );
370
+ if (!res) return { status: 0, body: null };
371
+ let json = null;
372
+ try {
373
+ json = JSON.parse(res.text);
374
+ } catch {
375
+ }
376
+ return { status: res.status, body: isObject(json) ? json : null };
377
+ }
378
+ function refusal3(answer, stage, hostname) {
379
+ if (answer.status === 401) return new DnsWriteError("token_invalid");
380
+ if (answer.status === 403)
381
+ return new DnsWriteError(stage === "reading" ? "zone_read_missing" : "dns_edit_missing");
382
+ if (answer.status === 409) return new DnsWriteError("conflict", { hostname });
383
+ return new DnsWriteError("unavailable");
384
+ }
385
+ function pageOf(body) {
386
+ const rows = body?.records;
387
+ if (!Array.isArray(rows)) throw new DnsWriteError("unavailable");
388
+ const records = rows.map((row) => {
389
+ if (!isObject(row) || typeof row.id !== "number" || typeof row.type !== "string" || typeof row.answer !== "string" || typeof row.fqdn !== "string" || !RECORD_TYPE3.test(row.type))
390
+ throw new DnsWriteError("unavailable");
391
+ return { id: String(row.id), type: row.type, content: row.answer, name: row.fqdn };
392
+ });
393
+ return { records, more: typeof body?.nextPage === "number" };
394
+ }
395
+ var namecom = {
396
+ host: "name-com",
397
+ /** Add the record to the Name.com domain that holds its name. An identical record is left as
398
+ * it is. Name.com has no proxy, so the outcome is `created` or `unchanged`. */
399
+ async addRecord({ token, record, fetch: doFetch = fetch }) {
400
+ const hostname = normalizeDnsName(record.name);
401
+ const basic = basicOf(token);
402
+ if (!basic) throw new DnsWriteError("token_invalid");
403
+ let zone;
404
+ let existing = [];
405
+ for (const candidate of zoneCandidates(hostname)) {
406
+ const path = `/domains/${encodeURIComponent(candidate)}/records`;
407
+ const first = await call3(doFetch, basic, `${path}?perPage=${PER_PAGE}`);
408
+ if (first.status === 404) continue;
409
+ if (first.status !== 200) throw refusal3(first, "reading", hostname);
410
+ zone = candidate;
411
+ let page = pageOf(first.body);
412
+ existing = page.records;
413
+ for (let next = 2; page.more && next <= MAX_PAGES; next++) {
414
+ const answer = await call3(doFetch, basic, `${path}?perPage=${PER_PAGE}&page=${next}`);
415
+ if (answer.status !== 200) throw refusal3(answer, "reading", hostname);
416
+ page = pageOf(answer.body);
417
+ existing = existing.concat(page.records);
418
+ }
419
+ if (page.more) throw new DnsWriteError("unavailable");
420
+ break;
421
+ }
422
+ if (!zone) throw new DnsWriteError("zone_not_found", { hostname });
423
+ const here = existing.filter(
424
+ (r) => r.name !== void 0 && normalizeDnsName(r.name) === hostname
425
+ );
426
+ const decision = decide(record, here, hostname);
427
+ if (decision.kind === "unchanged") return "unchanged";
428
+ const host = hostname === zone ? "@" : hostname.slice(0, -(zone.length + 1));
429
+ const created = await call3(doFetch, basic, `/domains/${encodeURIComponent(zone)}/records`, {
430
+ body: { host, type: record.type, answer: record.value, ttl: TTL }
431
+ });
432
+ if (created.status !== 200) throw refusal3(created, "writing", hostname);
433
+ const stored = created.body?.answer;
434
+ if (typeof stored !== "string" || !sameValue(record, { content: stored }))
435
+ throw new DnsWriteError("unavailable");
436
+ return "created";
437
+ }
438
+ };
439
+
440
+ // src/writers/porkbun.ts
441
+ var API4 = "https://api.porkbun.com/api/json/v3";
442
+ var TIMEOUT_MS4 = 1e4;
443
+ var MAX_BODY_BYTES4 = 256 * 1024;
444
+ var KEY_CODES = /* @__PURE__ */ new Set([
445
+ "API_KEY_REQUIRED",
446
+ "INVALID_API_KEYS_001",
447
+ "INVALID_TOKEN",
448
+ "INVALID_USER"
449
+ ]);
450
+ var ACCESS_CODES = /* @__PURE__ */ new Set(["API_ACCESS_DISABLED", "IP_NOT_ALLOWED", "DOMAIN_NOT_ALLOWED"]);
451
+ var NOT_A_ZONE_CODES = /* @__PURE__ */ new Set(["INVALID_DOMAIN", "DOMAIN_NOT_FOUND"]);
452
+ var ID2 = /^[0-9]{1,20}$/;
453
+ var RECORD_TYPE4 = /^[A-Z0-9]{1,12}$/;
454
+ function keysOf(token) {
455
+ const at = token.indexOf(":");
456
+ const key = token.slice(0, at);
457
+ const secret = token.slice(at + 1);
458
+ return at > 0 && secret && !/\s/.test(token) ? { key, secret } : null;
459
+ }
460
+ async function call4(doFetch, keys, path, send) {
461
+ const res = await fetchBounded(
462
+ doFetch,
463
+ `${API4}${path}`,
464
+ {
465
+ method: send ? "POST" : "GET",
466
+ headers: {
467
+ "X-API-Key": keys.key,
468
+ "X-Secret-API-Key": keys.secret,
469
+ Accept: "application/json",
470
+ ...send ? { "Content-Type": "application/json" } : {}
471
+ },
472
+ body: send ? JSON.stringify(send.body) : void 0
473
+ },
474
+ { timeoutMs: TIMEOUT_MS4, maxBytes: MAX_BODY_BYTES4 }
475
+ );
476
+ if (!res) return { code: "", ok: false, body: null };
477
+ let json = null;
478
+ try {
479
+ json = JSON.parse(res.text);
480
+ } catch {
481
+ }
482
+ const body = isObject(json) ? json : null;
483
+ return {
484
+ code: typeof body?.code === "string" ? body.code : "",
485
+ ok: res.status === 200 && body?.status === "SUCCESS",
486
+ body
487
+ };
488
+ }
489
+ function refusal4(answer, hostname) {
490
+ if (KEY_CODES.has(answer.code)) return new DnsWriteError("token_invalid");
491
+ if (ACCESS_CODES.has(answer.code)) return new DnsWriteError("dns_edit_missing");
492
+ if (answer.code === "RECORD_CONFLICT") return new DnsWriteError("conflict", { hostname });
493
+ return new DnsWriteError("unavailable");
494
+ }
495
+ function recordsOf3(body) {
496
+ const rows = body?.records;
497
+ if (!Array.isArray(rows)) throw new DnsWriteError("unavailable");
498
+ return rows.map((row) => {
499
+ if (!isObject(row) || typeof row.id !== "string" || typeof row.name !== "string" || typeof row.type !== "string" || typeof row.content !== "string" || !ID2.test(row.id) || !RECORD_TYPE4.test(row.type))
500
+ throw new DnsWriteError("unavailable");
501
+ return { id: row.id, type: row.type, content: row.content, name: row.name };
502
+ });
503
+ }
504
+ var porkbun = {
505
+ host: "porkbun",
506
+ /** Add the record to the Porkbun domain that holds its name. An identical record is left as
507
+ * it is. Porkbun has no proxy, so the outcome is `created` or `unchanged`. */
508
+ async addRecord({ token, record, comment, fetch: doFetch = fetch }) {
509
+ const hostname = normalizeDnsName(record.name);
510
+ const keys = keysOf(token);
511
+ if (!keys) throw new DnsWriteError("token_invalid");
512
+ let zone;
513
+ let existing = [];
514
+ for (const candidate of zoneCandidates(hostname)) {
515
+ const answer = await call4(doFetch, keys, `/dns/retrieve/${encodeURIComponent(candidate)}`);
516
+ if (answer.ok) {
517
+ zone = candidate;
518
+ existing = recordsOf3(answer.body).filter(
519
+ (r) => r.name !== void 0 && normalizeDnsName(r.name) === hostname
520
+ );
521
+ break;
522
+ }
523
+ if (!NOT_A_ZONE_CODES.has(answer.code)) throw refusal4(answer, hostname);
524
+ }
525
+ if (!zone) throw new DnsWriteError("zone_not_found", { hostname });
526
+ const decision = decide(record, existing, hostname);
527
+ if (decision.kind === "unchanged") return "unchanged";
528
+ const subdomain = hostname === zone ? "" : hostname.slice(0, -(zone.length + 1));
529
+ const created = await call4(doFetch, keys, `/dns/create/${encodeURIComponent(zone)}`, {
530
+ body: {
531
+ name: subdomain,
532
+ type: record.type,
533
+ content: record.value,
534
+ ...comment ? { notes: comment } : {}
535
+ }
536
+ });
537
+ if (created.code === "DUPLICATE_RECORD") return "unchanged";
538
+ if (!created.ok) throw refusal4(created, hostname);
539
+ return "created";
540
+ }
541
+ };
542
+
242
543
  // src/writers/index.ts
243
- var writers = { cloudflare };
544
+ var writers = {
545
+ cloudflare,
546
+ digitalocean,
547
+ "name-com": namecom,
548
+ porkbun
549
+ };
244
550
  // Annotate the CommonJS export names for ESM import in node:
245
551
  0 && (module.exports = {
246
552
  DnsWriteError,
247
553
  cloudflare,
554
+ digitalocean,
555
+ namecom,
556
+ porkbun,
248
557
  writers
249
558
  });
@@ -1,4 +1,5 @@
1
1
  import { D as DnsHostId } from '../hosts-B0_V4Ned.cjs';
2
+ import { F as FetchFn } from '../bounded-fetch-nozW2egX.cjs';
2
3
 
3
4
  interface DnsWriteRecord {
4
5
  type: "CNAME" | "TXT";
@@ -45,13 +46,19 @@ interface DnsWriter {
45
46
  record: DnsWriteRecord;
46
47
  /** Shown beside the record in the host's panel, where the host has such a field. */
47
48
  comment?: string;
48
- fetch?: typeof fetch;
49
+ fetch?: FetchFn;
49
50
  }): Promise<DnsWriteOutcome>;
50
51
  }
51
52
 
52
53
  declare const cloudflare: DnsWriter;
53
54
 
55
+ declare const digitalocean: DnsWriter;
56
+
57
+ declare const namecom: DnsWriter;
58
+
59
+ declare const porkbun: DnsWriter;
60
+
54
61
  /** The hosts that take a pasted token, by host id: `writers[host]` is undefined for the rest. */
55
62
  declare const writers: Partial<Record<DnsHostId, DnsWriter>>;
56
63
 
57
- export { DnsWriteError, type DnsWriteErrorCode, type DnsWriteOutcome, type DnsWriteRecord, type DnsWriter, cloudflare, writers };
64
+ export { DnsWriteError, type DnsWriteErrorCode, type DnsWriteOutcome, type DnsWriteRecord, type DnsWriter, FetchFn, cloudflare, digitalocean, namecom, porkbun, writers };
@@ -1,4 +1,5 @@
1
1
  import { D as DnsHostId } from '../hosts-B0_V4Ned.js';
2
+ import { F as FetchFn } from '../bounded-fetch-nozW2egX.js';
2
3
 
3
4
  interface DnsWriteRecord {
4
5
  type: "CNAME" | "TXT";
@@ -45,13 +46,19 @@ interface DnsWriter {
45
46
  record: DnsWriteRecord;
46
47
  /** Shown beside the record in the host's panel, where the host has such a field. */
47
48
  comment?: string;
48
- fetch?: typeof fetch;
49
+ fetch?: FetchFn;
49
50
  }): Promise<DnsWriteOutcome>;
50
51
  }
51
52
 
52
53
  declare const cloudflare: DnsWriter;
53
54
 
55
+ declare const digitalocean: DnsWriter;
56
+
57
+ declare const namecom: DnsWriter;
58
+
59
+ declare const porkbun: DnsWriter;
60
+
54
61
  /** The hosts that take a pasted token, by host id: `writers[host]` is undefined for the rest. */
55
62
  declare const writers: Partial<Record<DnsHostId, DnsWriter>>;
56
63
 
57
- export { DnsWriteError, type DnsWriteErrorCode, type DnsWriteOutcome, type DnsWriteRecord, type DnsWriter, cloudflare, writers };
64
+ export { DnsWriteError, type DnsWriteErrorCode, type DnsWriteOutcome, type DnsWriteRecord, type DnsWriter, FetchFn, cloudflare, digitalocean, namecom, porkbun, writers };
@@ -1,11 +1,17 @@
1
1
  import {
2
2
  DnsWriteError,
3
3
  cloudflare,
4
+ digitalocean,
5
+ namecom,
6
+ porkbun,
4
7
  writers
5
- } from "../chunk-FGM7S7GQ.js";
8
+ } from "../chunk-4XNRV7QR.js";
6
9
  import "../chunk-P2O7INDB.js";
7
10
  export {
8
11
  DnsWriteError,
9
12
  cloudflare,
13
+ digitalocean,
14
+ namecom,
15
+ porkbun,
10
16
  writers
11
17
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gusnips/one-click-dns",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
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",
@@ -79,7 +79,7 @@
79
79
  "access": "public"
80
80
  },
81
81
  "peerDependencies": {
82
- "@gusnips/server": ">=0.15.0"
82
+ "@gusnips/server": ">=0.14.3"
83
83
  },
84
84
  "devDependencies": {
85
85
  "@eslint/js": "^10.0.1",