@nictool/dns-resource-record 1.2.0 → 1.2.1

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/rr/ns.js CHANGED
@@ -8,7 +8,7 @@ export default class NS extends RR {
8
8
 
9
9
  /****** Resource record specific setters *******/
10
10
  setDname(val) {
11
- if (!val) throw new Error(`NS: dname is required, ${this.citeRFC()}`)
11
+ if (!val) this.throwHelp(`NS: dname is required`)
12
12
 
13
13
  this.isFullyQualified('NS', 'dname', val)
14
14
  this.isValidHostname('NS', 'dname', val)
package/rr/nsec.js CHANGED
@@ -8,8 +8,7 @@ export default class NSEC extends RR {
8
8
 
9
9
  /****** Resource record specific setters *******/
10
10
  setNextDomain(val) {
11
- if (!val)
12
- throw new Error(`NSEC: 'next domain' is required:, ${this.citeRFC()}`)
11
+ if (!val) this.throwHelp(`NSEC: 'next domain' is required:`)
13
12
 
14
13
  this.isFullyQualified('NSEC', 'next domain', val)
15
14
  this.isValidHostname('NSEC', 'next domain', val)
@@ -19,8 +18,7 @@ export default class NSEC extends RR {
19
18
  }
20
19
 
21
20
  setTypeBitMaps(val) {
22
- if (!val)
23
- throw new Error(`NSEC: 'type bit maps' is required, ${this.citeRFC()}`)
21
+ if (!val) this.throwHelp(`NSEC: 'type bit maps' is required`)
24
22
 
25
23
  this.set('type bit maps', val)
26
24
  }
package/rr/nsec3.js CHANGED
@@ -12,8 +12,7 @@ export default class NSEC3 extends RR {
12
12
  setHashAlgorithm(val) {
13
13
  // Hash Algorithm is a single octet.
14
14
  // The Hash Algorithm field is represented as an unsigned decimal integer.
15
- if (!val)
16
- throw new Error(`NSEC3: 'hash algorithm' is required, ${this.citeRFC()}`)
15
+ if (!val) this.throwHelp(`NSEC3: 'hash algorithm' is required`)
17
16
 
18
17
  this.is8bitInt('NSEC3', 'hash algorithm', val)
19
18
 
@@ -22,7 +21,7 @@ export default class NSEC3 extends RR {
22
21
 
23
22
  setFlags(val) {
24
23
  // The Flags field is represented as an unsigned decimal integer.
25
- if (!val) throw new Error(`NSEC3: 'flags' is required, ${this.citeRFC()}`)
24
+ if (!val) this.throwHelp(`NSEC3: 'flags' is required`)
26
25
 
27
26
  this.is8bitInt('NSEC3', 'flags', val)
28
27
 
@@ -31,8 +30,7 @@ export default class NSEC3 extends RR {
31
30
 
32
31
  setIterations(val) {
33
32
  // The Iterations field is represented as an unsigned decimal integer. 0-65535
34
- if (!val)
35
- throw new Error(`NSEC3: 'iterations' is required, ${this.citeRFC()}`)
33
+ if (!val) this.throwHelp(`NSEC3: 'iterations' is required`)
36
34
 
37
35
  this.is16bitInt('NSEC3', 'flags', val)
38
36
 
@@ -50,18 +48,14 @@ export default class NSEC3 extends RR {
50
48
  setNextHashedOwnerName(val) {
51
49
  // The Next Hashed Owner Name field is represented as an unpadded
52
50
  // sequence of case-insensitive base32 digits, without whitespace
53
- if (!val)
54
- throw new Error(
55
- `NSEC3: 'next hashed owner name' is required, ${this.citeRFC()}`,
56
- )
51
+ if (!val) this.throwHelp(`NSEC3: 'next hashed owner name' is required`)
57
52
 
58
53
  this.set('next hashed owner name', val)
59
54
  }
60
55
 
61
56
  setTypeBitMaps(val) {
62
57
  // The Type Bit Maps field is represented as a sequence of RR type mnemonics.
63
- if (!val)
64
- throw new Error(`NSEC3: 'type bit maps' is required, ${this.citeRFC()}`)
58
+ if (!val) this.throwHelp(`NSEC3: 'type bit maps' is required`)
65
59
 
66
60
  this.set('type bit maps', val)
67
61
  }
@@ -113,7 +107,7 @@ export default class NSEC3 extends RR {
113
107
 
114
108
  fromTinydns(opts) {
115
109
  const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
116
- if (n != 50) throw new Error('NSEC3 fromTinydns, invalid n')
110
+ if (n != 50) this.throwHelp('NSEC3 fromTinydns, invalid n')
117
111
 
118
112
  const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
119
113
 
package/rr/nsec3param.js CHANGED
@@ -7,13 +7,10 @@ export default class NSEC3PARAM extends RR {
7
7
  }
8
8
 
9
9
  /****** Resource record specific setters *******/
10
- setHashAlgoritm(val) {
10
+ setHashAlgorithm(val) {
11
11
  // Hash Algorithm is a single octet.
12
12
  // The Hash Algorithm field is represented as an unsigned decimal integer.
13
- if (!val)
14
- throw new Error(
15
- `NSEC3PARAM: 'hash algorithm' is required, ${this.citeRFC()}`,
16
- )
13
+ if (!val) this.throwHelp(`NSEC3PARAM: 'hash algorithm' is required`)
17
14
 
18
15
  this.is8bitInt('NSEC3PARAM', 'hash algorithm', val)
19
16
 
@@ -22,8 +19,7 @@ export default class NSEC3PARAM extends RR {
22
19
 
23
20
  setFlags(val) {
24
21
  // The Flags field is represented as an unsigned decimal integer.
25
- if (!val)
26
- throw new Error(`NSEC3PARAM: 'flags' is required, ${this.citeRFC()}`)
22
+ if (!val) this.throwHelp(`NSEC3PARAM: 'flags' is required`)
27
23
 
28
24
  this.is8bitInt('NSEC3PARAM', 'flags', val)
29
25
 
@@ -32,8 +28,7 @@ export default class NSEC3PARAM extends RR {
32
28
 
33
29
  setIterations(val) {
34
30
  // The Iterations field is represented as an unsigned decimal integer. 0-65535
35
- if (!val)
36
- throw new Error(`NSEC3PARAM: 'iterations' is required, ${this.citeRFC()}`)
31
+ if (!val) this.throwHelp(`NSEC3PARAM: 'iterations' is required`)
37
32
 
38
33
  this.is16bitInt('NSEC3PARAM', 'iterations', val)
39
34
 
package/rr/nxt.js CHANGED
@@ -8,8 +8,7 @@ export default class NXT extends RR {
8
8
 
9
9
  /****** Resource record specific setters *******/
10
10
  setNextDomain(val) {
11
- if (!val)
12
- throw new Error(`NXT: 'next domain' is required:, ${this.citeRFC()}`)
11
+ if (!val) this.throwHelp(`NXT: 'next domain' is required`)
13
12
 
14
13
  this.isFullyQualified('NXT', 'next domain', val)
15
14
  this.isValidHostname('NXT', 'next domain', val)
@@ -19,8 +18,7 @@ export default class NXT extends RR {
19
18
  }
20
19
 
21
20
  setTypeBitMap(val) {
22
- if (!val)
23
- throw new Error(`NXT: 'type bit map' is required, ${this.citeRFC()}`)
21
+ if (!val) this.throwHelp(`NXT: 'type bit map' is required`)
24
22
 
25
23
  this.set('type bit map', val)
26
24
  }
package/rr/openpgpkey.js CHANGED
@@ -27,15 +27,19 @@ export default class OPENPGPKEY extends RR {
27
27
  }
28
28
 
29
29
  /****** IMPORTERS *******/
30
- fromBind(str) {
30
+ fromBind(obj) {
31
31
  // test.example.com 3600 IN OPENPGPKEY <base64 public key>
32
- const [owner, ttl, c, type, privatekey] = str.split(/\s+/)
32
+ // eslint-disable-next-line no-unused-vars
33
+ const [ignore, owner, ttl, c, type, publickey] = obj.bindline.match(
34
+ /^([\S]+)\s+(\d+)\s+(\w+)\s+(\w+)\s+([\W\w]*)$/,
35
+ )
36
+
33
37
  return new OPENPGPKEY({
34
38
  owner,
35
39
  ttl: parseInt(ttl, 10),
36
40
  class: c,
37
41
  type: type,
38
- 'private key': privatekey,
42
+ 'public key': publickey.trim(),
39
43
  })
40
44
  }
41
45
 
package/rr/rrsig.js CHANGED
@@ -8,9 +8,8 @@ export default class RRSIG extends RR {
8
8
  /****** Resource record specific setters *******/
9
9
  setTypeCovered(val) {
10
10
  // a 2 octet Type Covered field
11
- if (!val) throw new Error(`RRSIG: 'type covered' is required`)
12
- if (val.length > 2)
13
- throw new Error(`RRSIG: 'type covered' is too long, ${this.citeRFC()}`)
11
+ if (!val) this.throwHelp(`RRSIG: 'type covered' is required`)
12
+ if (val.length > 2) this.throwHelp(`RRSIG: 'type covered' is too long`)
14
13
 
15
14
  this.set('type covered', val)
16
15
  }
@@ -19,7 +18,7 @@ export default class RRSIG extends RR {
19
18
  // a 1 octet Algorithm field
20
19
  // 1=RSA/MD5, 2=DH, 3=RRSIGA/SHA-1, 4=EC, 5=RSA/SHA-1
21
20
  if (![1, 2, 3, 4, 5, 253, 254].includes(val))
22
- throw new Error(`RRSIG: algorithm invalid, ${this.citeRFC()}`)
21
+ this.throwHelp(`RRSIG: algorithm invalid`)
23
22
 
24
23
  this.set('algorithm', val)
25
24
  }
package/rr/sig.js CHANGED
@@ -8,7 +8,7 @@ export default class SIG extends RR {
8
8
  /****** Resource record specific setters *******/
9
9
  setTypeCovered(val) {
10
10
  // a 2 octet Type Covered field
11
- if (!val) throw new Error(`SIG: 'type covered' is required`)
11
+ if (!val) this.throwHelp(`SIG: 'type covered' is required`)
12
12
 
13
13
  this.set('type covered', val)
14
14
  }
package/rr/smimea.js CHANGED
@@ -8,21 +8,19 @@ export default class SMIMEA extends RR {
8
8
  /****** Resource record specific setters *******/
9
9
  setCertificateUsage(val) {
10
10
  if (![0, 1, 2, 3].includes(val))
11
- throw new Error(`SMIMEA: certificate usage invalid, ${this.citeRFC()}`)
11
+ this.throwHelp(`SMIMEA: certificate usage invalid`)
12
12
 
13
13
  this.set('certificate usage', val)
14
14
  }
15
15
 
16
16
  setSelector(val) {
17
- if (![0, 1].includes(val))
18
- throw new Error(`SMIMEA: selector invalid, ${this.citeRFC()}`)
17
+ if (![0, 1].includes(val)) this.throwHelp(`SMIMEA: selector invalid`)
19
18
 
20
19
  this.set('selector', val)
21
20
  }
22
21
 
23
22
  setMatchingType(val) {
24
- if (![0, 1, 2].includes(val))
25
- throw new Error(`SMIMEA: matching type, ${this.citeRFC()}`)
23
+ if (![0, 1, 2].includes(val)) this.throwHelp(`SMIMEA: matching type`)
26
24
 
27
25
  this.set('matching type', val)
28
26
  }
package/rr/soa.js CHANGED
@@ -28,8 +28,7 @@ export default class SOA extends RR {
28
28
  // RNAME (email of admin) (escape . with \)
29
29
  this.isValidHostname('SOA', 'RNAME', val)
30
30
  this.isFullyQualified('SOA', 'RNAME', val)
31
- if (/@/.test(val))
32
- throw new Error(`SOA rname replaces @ with a . (dot), ${this.citeRFC()}`)
31
+ if (/@/.test(val)) this.throwHelp(`SOA rname replaces @ with a . (dot)`)
33
32
 
34
33
  // RFC 4034: letters in the DNS names are lower cased
35
34
  this.set('rname', val.toLowerCase())
package/rr/spf.js CHANGED
@@ -34,7 +34,7 @@ export default class SPF extends TXT {
34
34
  fromTinydns(opts) {
35
35
  // SPF via generic, :fqdn:n:rdata:ttl:timestamp:lo
36
36
  const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
37
- if (n != 99) throw new Error('SPF fromTinydns, invalid n')
37
+ if (n != 99) this.throwHelp('SPF fromTinydns, invalid n')
38
38
 
39
39
  return new SPF({
40
40
  type: 'SPF',
package/rr/srv.js CHANGED
@@ -1,4 +1,4 @@
1
- import net from 'net'
1
+ import net from 'node:net'
2
2
 
3
3
  import RR from '../rr.js'
4
4
  import * as TINYDNS from '../lib/tinydns.js'
@@ -28,10 +28,10 @@ export default class SRV extends RR {
28
28
  }
29
29
 
30
30
  setTarget(val) {
31
- if (!val) throw new Error(`SRV: target is required, ${this.citeRFC()}`)
31
+ if (!val) this.throwHelp(`SRV: target is required`)
32
32
 
33
33
  if (net.isIPv4(val) || net.isIPv6(val))
34
- throw new Error(`SRV: target must be a FQDN, ${this.citeRFC()}`)
34
+ this.throwHelp(`SRV: target must be a FQDN`)
35
35
 
36
36
  this.isFullyQualified('SRV', 'target', val)
37
37
  this.isValidHostname('SRV', 'target', val)
@@ -69,7 +69,7 @@ export default class SRV extends RR {
69
69
  } else {
70
70
  // tinydns generic record format
71
71
  ;[fqdn, n, rdata, ttl, ts, loc] = str.substring(1).split(':')
72
- if (n != 33) throw new Error('SRV fromTinydns: invalid n')
72
+ if (n != 33) this.throwHelp('SRV fromTinydns: invalid n')
73
73
 
74
74
  pri = TINYDNS.octalToUInt16(rdata.substring(0, 8))
75
75
  weight = TINYDNS.octalToUInt16(rdata.substring(8, 16))
package/rr/sshfp.js CHANGED
@@ -45,7 +45,7 @@ export default class SSHFP extends RR {
45
45
  fromTinydns(opts) {
46
46
  // SSHFP via generic, :fqdn:n:rdata:ttl:timestamp:lo
47
47
  const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
48
- if (n != 44) throw new Error('SSHFP fromTinydns, invalid n')
48
+ if (n != 44) this.throwHelp('SSHFP fromTinydns, invalid n')
49
49
 
50
50
  return new SSHFP({
51
51
  owner: this.fullyQualify(fqdn),
package/rr/svcb.js ADDED
@@ -0,0 +1,64 @@
1
+ import RR from '../rr.js'
2
+
3
+ export default class SVCB extends RR {
4
+ constructor(opts) {
5
+ super(opts)
6
+ }
7
+
8
+ /****** Resource record specific setters *******/
9
+ setPriority(val) {
10
+ this.is16bitInt('SVCB', 'priority', val)
11
+
12
+ this.set('priority', val)
13
+ }
14
+
15
+ setTargetName(val) {
16
+ // this.isFullyQualified('SVCB', 'target name', val)
17
+ // this.isValidHostname('SVCB', 'target name', val)
18
+
19
+ // RFC 4034: letters in the DNS names are lower cased
20
+ this.set('target name', val.toLowerCase())
21
+ }
22
+
23
+ setParams(val) {
24
+ // if (!val) throw new Error(`SVCB: params is required`)
25
+
26
+ this.set('params', val)
27
+ }
28
+
29
+ getDescription() {
30
+ return 'Service Binding'
31
+ }
32
+
33
+ getRdataFields(arg) {
34
+ return ['priority', 'target name', 'params']
35
+ }
36
+
37
+ getRFCs() {
38
+ return [9460]
39
+ }
40
+
41
+ getTypeId() {
42
+ return 64
43
+ }
44
+
45
+ /****** IMPORTERS *******/
46
+
47
+ fromBind(opts) {
48
+ // test.example.com 3600 IN SVCB Priority TargetName Params
49
+ // _8443._foo.api.example.com. 7200 IN SVCB 0 svc4.example.net.
50
+ // svc4.example.net. 7200 IN SVCB 3 svc4.example.net. ( alpn="bar" port="8004" )
51
+ const [owner, ttl, c, type, pri, fqdn] = opts.bindline.split(/\s+/)
52
+ return new SVCB({
53
+ owner,
54
+ ttl: parseInt(ttl, 10),
55
+ class: c,
56
+ type,
57
+ priority: parseInt(pri, 10),
58
+ 'target name': fqdn,
59
+ params: opts.bindline.split(/\s+/).slice(6).join(' ').trim(),
60
+ })
61
+ }
62
+
63
+ /****** EXPORTERS *******/
64
+ }
package/rr/tlsa.js CHANGED
@@ -10,21 +10,19 @@ export default class TLSA extends RR {
10
10
  /****** Resource record specific setters *******/
11
11
  setCertificateUsage(val) {
12
12
  if (![0, 1, 2, 3].includes(val))
13
- throw new Error(`TLSA: certificate usage invalid, ${this.citeRFC()}`)
13
+ this.throwHelp(`TLSA: certificate usage invalid`)
14
14
 
15
15
  this.set('certificate usage', val)
16
16
  }
17
17
 
18
18
  setSelector(val) {
19
- if (![0, 1].includes(val))
20
- throw new Error(`TLSA: selector invalid, ${this.citeRFC()}`)
19
+ if (![0, 1].includes(val)) this.throwHelp(`TLSA: selector invalid`)
21
20
 
22
21
  this.set('selector', val)
23
22
  }
24
23
 
25
24
  setMatchingType(val) {
26
- if (![0, 1, 2].includes(val))
27
- throw new Error(`TLSA: matching type, ${this.citeRFC()}`)
25
+ if (![0, 1, 2].includes(val)) this.throwHelp(`TLSA: matching type`)
28
26
 
29
27
  this.set('matching type', val)
30
28
  }
@@ -65,7 +63,7 @@ export default class TLSA extends RR {
65
63
  const match = opts.bindline.split(
66
64
  /^([^\s]+)\s+([0-9]+)\s+(\w+)\s+(\w+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+(.*?)\s*$/,
67
65
  )
68
- if (!match) throw new Error(`unable to parse TLSA: ${opts.bindline}`)
66
+ if (!match) this.throwHelp(`unable to parse TLSA: ${opts.bindline}`)
69
67
  const [owner, ttl, c, type, usage, selector, matchtype, cad] =
70
68
  match.slice(1)
71
69
  return new TLSA({
@@ -82,7 +80,7 @@ export default class TLSA extends RR {
82
80
 
83
81
  fromTinydns(opts) {
84
82
  const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
85
- if (n != 52) throw new Error('TLSA fromTinydns, invalid n')
83
+ if (n != 52) this.throwHelp('TLSA fromTinydns, invalid n')
86
84
 
87
85
  const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
88
86
 
package/rr/tsig.js CHANGED
@@ -13,7 +13,15 @@ export default class TSIG extends RR {
13
13
  }
14
14
 
15
15
  getRdataFields(arg) {
16
- return ['algorithm name', 'time signed', 'fudge', 'mac', 'original id', 'error', 'other']
16
+ return [
17
+ 'algorithm name',
18
+ 'time signed',
19
+ 'fudge',
20
+ 'mac',
21
+ 'original id',
22
+ 'error',
23
+ 'other',
24
+ ]
17
25
  }
18
26
 
19
27
  getRFCs() {
@@ -34,7 +42,7 @@ export default class TSIG extends RR {
34
42
  ttl: parseInt(ttl, 10),
35
43
  class: c,
36
44
  type: type,
37
- 'algorithm': algorithm,
45
+ algorithm: algorithm,
38
46
  // 'time signed': opts.bindline,
39
47
  // fudge
40
48
  // mac
package/rr/txt.js CHANGED
@@ -54,7 +54,7 @@ export default class TXT extends RR {
54
54
  // generic: :fqdn:n:rdata:ttl:timestamp:location
55
55
  // eslint-disable-next-line prefer-const
56
56
  let [fqdn, n, rdata, ttl, ts, loc] = str.substring(1).split(':')
57
- if (n != 16) throw new Error('TXT fromTinydns, invalid n')
57
+ if (n != 16) this.throwHelp('TXT fromTinydns, invalid n')
58
58
 
59
59
  rdata = TINYDNS.octalToChar(rdata)
60
60
  let s = ''
@@ -73,7 +73,7 @@ export default class TXT extends RR {
73
73
  const match = opts.bindline.split(
74
74
  /^([^\s]+)\s+([0-9]+)\s+(\w+)\s+(\w+)\s+?\s*(.*?)\s*$/,
75
75
  )
76
- if (!match) throw new Error(`unable to parse TXT: ${opts.bindline}`)
76
+ if (!match) this.throwHelp(`unable to parse TXT: ${opts.bindline}`)
77
77
  const [owner, ttl, c, type, rdata] = match.slice(1)
78
78
 
79
79
  return new this.constructor({
package/rr/uri.js CHANGED
@@ -21,7 +21,7 @@ export default class URI extends RR {
21
21
  }
22
22
 
23
23
  setTarget(val) {
24
- if (!val) throw new Error(`URI: target is required, ${this.citeRFC()}`)
24
+ if (!val) this.throwHelp(`URI: target is required`)
25
25
 
26
26
  this.set('target', val)
27
27
  }
@@ -30,7 +30,7 @@ export default class URI extends RR {
30
30
  fromTinydns(opts) {
31
31
  // URI via generic, :fqdn:n:rdata:ttl:timestamp:lo
32
32
  const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
33
- if (n != 256) throw new Error('URI fromTinydns, invalid n')
33
+ if (n != 256) this.throwHelp('URI fromTinydns, invalid n')
34
34
 
35
35
  return new URI({
36
36
  type: 'URI',
package/rr/wks.js CHANGED
@@ -28,15 +28,16 @@ export default class WKS extends RR {
28
28
 
29
29
  fromBind(opts) {
30
30
  // test.example.com 3600 IN WKS 192.168.1.1 TCP 25
31
- const [owner, ttl, c, type, address, protocol, bitmap] = opts.bindline.split(/\s+/)
31
+ const [owner, ttl, c, type, address, protocol, bitmap] =
32
+ opts.bindline.split(/\s+/)
32
33
  return new WKS({
33
34
  owner,
34
35
  ttl: parseInt(ttl, 10),
35
36
  class: c,
36
37
  type,
37
- address, // 32-bit int
38
+ address, // 32-bit int
38
39
  protocol, // 8-bit int, 6=TCP, 17=UDP
39
- bitmap, // var len bit map, must be multiple of 8
40
+ bitmap, // var len bit map, must be multiple of 8
40
41
  })
41
42
  }
42
43
 
package/rr.js CHANGED
@@ -1,3 +1,5 @@
1
+ import util from 'node:util'
2
+
1
3
  export default class RR extends Map {
2
4
  constructor(opts) {
3
5
  super()
@@ -21,7 +23,7 @@ export default class RR extends Map {
21
23
  for (const f of this.getFields('rdata')) {
22
24
  const fnName = `set${this.ucfirst(f)}`
23
25
  if (this[fnName] === undefined)
24
- throw new Error(`Missing ${fnName} in class ${this.get('type')}`)
26
+ this.throwHelp(`Missing ${fnName} in class ${this.get('type')}`)
25
27
  this[fnName](opts[f])
26
28
  }
27
29
 
@@ -51,7 +53,7 @@ export default class RR extends Map {
51
53
  this.set('class', c)
52
54
  break
53
55
  default:
54
- throw new Error(`invalid class ${c}`)
56
+ this.throwHelp(`invalid class ${c}`)
55
57
  }
56
58
  }
57
59
 
@@ -74,20 +76,20 @@ export default class RR extends Map {
74
76
  }
75
77
 
76
78
  setOwner(n) {
77
- if (n === undefined) throw new Error(`owner is required`)
79
+ if (n === undefined) this.throwHelp(`owner is required`)
78
80
 
79
81
  if (n.length < 1 || n.length > 255)
80
- throw new Error(
82
+ this.throwHelp(
81
83
  'Domain names must have 1-255 octets (characters): RFC 2181',
82
84
  )
83
85
 
84
- this.isFullyQualified('', 'owner', n)
86
+ this.isFullyQualified(this.constructor.name, 'owner', n)
85
87
  this.hasValidLabels(n)
86
88
 
87
89
  // wildcard records: RFC 1034, 4592
88
90
  if (/\*/.test(n)) {
89
91
  if (!/^\*\./.test(n) && !/\.\*\./.test(n))
90
- throw new Error('only *.something or * (by itself) is a valid wildcard')
92
+ this.throwHelp('only *.something or * (by itself) is a valid wildcard')
91
93
  }
92
94
 
93
95
  this.set('owner', n.toLowerCase())
@@ -97,11 +99,11 @@ export default class RR extends Map {
97
99
  if (t === undefined) t = this?.default?.ttl
98
100
  if (t === undefined) {
99
101
  if (['SOA', 'SSHPF'].includes(this.get('type'))) return
100
- throw new Error('TTL is required, no default available')
102
+ this.throwHelp('TTL is required, no default available')
101
103
  }
102
104
 
103
105
  if (typeof t !== 'number')
104
- throw new Error(`TTL must be numeric (${typeof t})`)
106
+ this.throwHelp(`TTL must be numeric (${typeof t})`)
105
107
 
106
108
  // RFC 1035, 2181
107
109
  this.is32bitInt(this.owner, 'TTL', t)
@@ -113,17 +115,27 @@ export default class RR extends Map {
113
115
  switch (t) {
114
116
  case '':
115
117
  case undefined:
116
- throw new Error(`type is required`)
118
+ this.throwHelp(`type is required`)
117
119
  }
118
120
 
119
121
  if (t.toUpperCase() !== this.constructor.name)
120
- throw new Error(`type ${t} doesn't match ${this.constructor.name}`)
122
+ this.throwHelp(`type ${t} doesn't match ${this.constructor.name}`)
121
123
 
122
124
  this.set('type', t.toUpperCase())
123
125
  }
124
126
 
127
+ throwHelp(e) {
128
+ if (this.constructor.name === 'RR') throw new Error(e)
129
+
130
+ const example = this.getCanonical
131
+ ? `Example ${this.constructor.name}:\n${util.inspect(this.getCanonical(), { depth: null })}\n\n`
132
+ : `${this.constructor.name} records have the fields: ${this.getFields().join(', ')}\n\n`
133
+
134
+ throw new Error(`${e}\n\n${example}${this.citeRFC()}\n`)
135
+ }
136
+
125
137
  citeRFC() {
126
- return `see RFC ${this.getRFCs()}`
138
+ return `see RFC${this.getRFCs().length > 1 ? 's' : ''} ${this.getRFCs()}`
127
139
  }
128
140
 
129
141
  fullyQualify(hostname, origin) {
@@ -194,7 +206,7 @@ export default class RR extends Map {
194
206
 
195
207
  getFQDN(field, zone_opts = {}) {
196
208
  let fqdn = this.get(field)
197
- if (!fqdn) throw new Error(`empty value for field ${field}`)
209
+ if (!fqdn) this.throwHelp(`empty value for field ${field}`)
198
210
  if (!fqdn.endsWith('.')) fqdn += '.'
199
211
 
200
212
  if (zone_opts.hide?.origin && zone_opts.origin) {
@@ -235,7 +247,7 @@ export default class RR extends Map {
235
247
  const fq = hostname.endsWith('.') ? hostname.slice(0, -1) : hostname
236
248
  for (const label of fq.split('.')) {
237
249
  if (label.length < 1 || label.length > 63)
238
- throw new Error('Labels must have 1-63 octets (characters), RFC 2181')
250
+ this.throwHelp('Labels must have 1-63 octets (characters), RFC 2181')
239
251
  }
240
252
  }
241
253
 
@@ -248,7 +260,7 @@ export default class RR extends Map {
248
260
  )
249
261
  return true
250
262
 
251
- throw new Error(
263
+ this.throwHelp(
252
264
  `${type} ${field} must be a 8-bit integer (in the range 0-255)`,
253
265
  )
254
266
  }
@@ -262,7 +274,7 @@ export default class RR extends Map {
262
274
  )
263
275
  return true
264
276
 
265
- throw new Error(
277
+ this.throwHelp(
266
278
  `${type} ${field} must be a 16-bit integer (in the range 0-65535)`,
267
279
  )
268
280
  }
@@ -276,7 +288,7 @@ export default class RR extends Map {
276
288
  )
277
289
  return true
278
290
 
279
- throw new Error(
291
+ this.throwHelp(
280
292
  `${type} ${field} must be a 32-bit integer (in the range 0-2147483647)`,
281
293
  )
282
294
  }
@@ -285,10 +297,10 @@ export default class RR extends Map {
285
297
  return /^["']/.test(val) && /["']$/.test(val)
286
298
  }
287
299
 
288
- isFullyQualified(type, blah, hostname) {
300
+ isFullyQualified(type, field, hostname) {
289
301
  if (hostname.endsWith('.')) return true
290
302
 
291
- throw new Error(`${type}: ${blah} must be fully qualified`)
303
+ this.throwHelp(`${type}: ${field} must be fully qualified`)
292
304
  }
293
305
 
294
306
  isValidHostname(type, field, hostname) {
@@ -296,7 +308,7 @@ export default class RR extends Map {
296
308
  if (!allowed.test(hostname)) return true
297
309
 
298
310
  const matches = allowed.exec(hostname)
299
- throw new Error(
311
+ this.throwHelp(
300
312
  `${type}, ${field} has invalid hostname character (${matches[0]})`,
301
313
  )
302
314
  }
@@ -320,7 +332,7 @@ export default class RR extends Map {
320
332
  }
321
333
 
322
334
  toMaraGeneric() {
323
- // throw new Error(`\nMaraDNS does not support ${type} records yet and this package does not support MaraDNS generic records. Yet.\n`)
335
+ // this.throwHelp(`\nMaraDNS does not support ${type} records yet and this package does not support MaraDNS generic records. Yet.\n`)
324
336
  return `${this.get('owner')}\t+${this.get('ttl')}\tRAW ${this.getTypeId()}\t'${this.getRdataFields()
325
337
  .map((f) => this.getQuoted(f))
326
338
  .join(' ')}' ~\n`
package/.prettierrc.yml DELETED
@@ -1,3 +0,0 @@
1
- trailingComma: 'all'
2
- semi: false
3
- singleQuote: true